Angular Tutorial: Modifying the CSS transform property of HTML elements within a component directly

Currently, I'm in the process of developing an analog clock for a project using Angular.

My challenge is figuring out how to dynamically update the sec/min/hour handlers on the clock based on the current time by manipulating the style.transform property for each element.

This snippet features my progress so far:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-clock',
  templateUrl: './clock.component.html',
  styleUrls: ['./clock.component.css']
})
export class ClockComponent implements OnInit {
  constructor() { }
  ngOnInit() { }
}
body {
  margin: 0;
}

.wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  width: 100%;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
}

.clock {
  width: 150px;
  height: 150px;
  background-color: #20b7af;
  border: 12px solid white;
  box-shadow: 0 0 30px rgb(202, 202, 202);
  border-radius: 50%;
  position: relative;
}

#sec-hand {
  width: 1px;
  height: 50%;
  background-color: rgb(255, 255, 255);
  transform-origin: 50% 80%;
  position: absolute;
  top: 10%;
  left: 50%;
}

#min-hand {
  width: 5px;
  height: 40%;
  background-color: rgb(255, 255, 255);
  transform-origin: 50% 80%;
  position: absolute;
  top: 18%;
  left: calc(50% - 1px);
}

#hr-hand {
  width: 3px;
  height: 25%;
  background-color: rgb(255, 255, 255);
  transform-origin: 50% 80%;
  position: absolute;
  top: 30%;
  left: calc(50% + -2px);
}

.num {
  height: 100%;
  position: absolute;
  left: calc(50% - 0.5em);
  font-size: 10px;
}

/* Repeat rotation and counter-rotation transformation for indicating numbers */
.num1 {
  transform: rotate(30deg);
}

.num1 div {
  transform: rotate(-30deg);
}

...

.num12 {
  transform: rotate(0deg);
}

.num12 div {
  transform: rotate(-0deg);
}

.as-console-wrapper {
  display: none !important;
}
...

Answer №1

You have the option to utilize a template variable on various elements such as sec-hand and then obtain a reference to it within your component:

<div id="sec-hand" #secHand></div>

Subsequently, in your component use @ViewChild to acquire the reference:

@ViewChild('secHand') el: ElementRef;

Following this step, you can access the DOM element (refer to the functional example at Stackblitz). The given example simply incorporates a class addition, so ensure to check the documentation to achieve specific tasks like utilizing setStyle for transformations.

import { Component, AfterViewInit, ViewChild, Renderer2, ElementRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewInit  {

  @ViewChild('secHand') el: ElementRef;

  constructor(private renderer: Renderer2) {}

  ngAfterViewInit() {
    this.renderer.addClass(this.el.nativeElement, 'example');
  }
}

Answer №2

To enhance the functionality of your clock, ensure you include refs for the three hands in your HTML template:

<div id="hr-hand" #hrHand></div>
<div id="min-hand" #minHand></div>
<div id="sec-hand" #secHand></div>

You can then initialize and utilize these references within your component by utilizing @ViewChild to dynamically update the transform: rotate(...) property. It is recommended to use a Renderer2 renderer for improved security against XSS attacks:

import { Component, OnInit, Renderer2 } from '@angular/core';

@Component({
    selector: 'app-clock',
    templateUrl: './clock.component.html',
    styleUrls: ['./clock.component.css']
})
export class ClockComponent implements OnInit {

    @ViewChild('hrHand') hrHandRef: ElementRef;
    @ViewChild('minHand') minHandRef: ElementRef;
    @ViewChild('secHand') secHandRef: ElementRef;

    constructor(
        private renderer: Renderer2
    ) { }

    ngOnInit() {
       ...
    }

    updateHands() {
        // Directly (not recommended):
        // this.hrHandRef.nativeElement.style.transform = `rotate(${ hrAngle }deg)`;
        // this.minHandRef.nativeElement.style.transform = `rotate(${ minAngle }deg)`;
        // this.secHandRef.nativeElement.style.transform = `rotate(${ secAngle }deg)`;

        // Using a renderer (recommended):
        this.renderer.setStyle(this.hrHandRef.nativeElement, 'transform', `rotate(${ hrAngle }deg)`;
        this.renderer.setStyle(this.minHandRef.nativeElement, 'transform', `rotate(${ minAngle }deg)`;
        this.renderer.setStyle(this.secHandRef.nativeElement, 'transform', `rotate(${ secAngle }deg)`;
    }
}

Alternatively, you can utilize ngStyle by adding three properties within the component containing each hand's angle.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Manipulating the DOM by nesting an icon within a button element in HTML

Currently working on my todo list project and I have a question about using innerHTML. I'm curious if I can include an icon inside of a button tag like this: btn.innerHTML = '<i class="fas fa-times fa-lg"></i>'; So, wo ...

What are some ways to incorporate advanced/nested type variables when using arrow functions?

Is there a way to use "advanced/nested" type variables, similar to how T is utilized in this function declaration, when working with arrow functions? function wrapInObject<T>(key: string) { return (x: T) => ({ [key]: x }); } I attempted to ach ...

Accessing properties within nested objects in a class

In my Angular 7 application, I have two object classes filled with data - employee and company (data retrieved through a web API from a database). The Employee class has fields - emp_id, name, surname, and a company object. The Company class has - c_id, ...

How to Align HTML Menu in the Middle of the Page

I've been struggling to center my menu on the page. I tried setting the display to block and using margin auto for left and right, but it's not working as expected. You can see the issue in this JSFiddle. Any help would be appreciated. <ul id ...

Center the element vertically if its height is less than the container's height, but let its height become 100% if the container's height is

I am trying to achieve a layout where an element (.figure) is centered horizontally when it is shorter than its container (.timeline-content), but matches the height of its container when longer. The height of the container changes based on its parent. T ...

A guide on wrapping text within a Material-UI MenuItem

I am struggling to display text in a popover in multiple lines for UI reasons. I have tried updating the code but so far, I have not been successful. Any suggestions? <Popover anchorEl={target} open={open} anchorOrigin={{ horizontal: 'middle& ...

Updates to TypeScript 2.3.1 creating disruptions in SystemJS plunk

Check out this official Angular + TypeScript plunk using SystemJS 0.19.31, now updated to TypeScript 2.3.0. However, changing the SystemJS configuration in the same plunk to TypeScript 2.3.1 or 2.3.2 'typescript': 'npm:<a href="/cdn-cgi ...

peculiar coding in HTML (HTML_ASG HTML_TAG, SYN_BLK, JS_ACV, etc..)

I created a website for a client and everything was working perfectly on my end. However, they are experiencing errors on 3 of their Windows machines running IE8 where the ElementById cannot be found. Upon inspecting the html-source, I discovered that ther ...

How do I create a left-to-right navigation bar for my web form?

Just starting out with Asp.net and now trying to create a right-to-left navbar. I've tried some code but everything ends up being left to right. ...

What is the best way to implement pipes and incorporate reusable action buttons in a Mat-table component for maximum reusability?

I am seeking assistance in creating a reusable component for the Angular Material Mat-table. I have made progress on loading data from the parent component to the child component, as can be seen in StackBlitz, but I now want to apply pipes to the data bef ...

Using TypeScript to deserialize JSON into a Discriminated Union

Consider the following Typescript code snippet: class Excel { Password: string; Sheet: number; } class Csv { Separator: string; Encoding: string; } type FileType = Excel | Csv let input = '{"Separator": ",", "Encoding": "UTF-8"}&ap ...

Automatically save a dropdown menu selection

Is there a way to automatically save the data selected in a drop down list without having to click on a save button? public ActionResult SelectFeedBack(int id) { YelloAdminDbContext db = new YelloAdminDbContext(); ViewBag.FeedBack ...

Is there a way to position my image and text side by side?

My current objective revolves around implementing a specific design, as illustrated in this image. The issue I'm encountering in my code pertains to the utilization of the bootstrap grid system for ease of layout. However, when I incorporate both tex ...

Looking to learn how to replicate data effortlessly with either javascript or jquery?

I am currently trying to figure out how close I am to successfully cloning this div. Honestly, I am a bit lost at this point and could really use some assistance. Should I consider using jQuery for this task? <div id="question20">20. Details of Chi ...

Set up dynamic restrictions for the length of an HTML paragraph with PHP

I am attempting to dynamically set the limit of content retrieved from a database in PHP. Specifically, I need to trim the input from the database before assigning it to an HTML paragraph. I attempted to use the substr function but was unsuccessful. Can y ...

No results returned by Mongoose/MongoDB GeoJSON query

I have a Schema (Tour) which includes a GeoJSON Point type property called location. location: { type: { type: String, enum: ['Point'], required: true }, coordinates: { type: [Number], required: true ...

Using Express, Node, and JQuery to handle form submissions

I am struggling with form submissions while working on a web app using HTML, Express, and Node.js. Despite being new to these technologies, I have created a script that generates a dynamic form based on certain factors: $FormContainer.html(''); ...

What's the best way to track changes in multiple form fields simultaneously in Angular?

Situation I have a form with 8 fields, but I want to monitor changes in just three of them to apply the same function. I don't want to set up individual subscriptions for each field like this: this.headerForm.get('start').valueChanges.subsc ...

Styling an HTML table with two columns: one column displaying an image, and the other column containing information related to the image

I have a concept that involves creating a table with 2 columns. The left column will feature an image, while the right column will display data about the image in 6 rows. ________________________________ | |_______________| | | ...

Alerts in Angular templates of inherited class in WebStorm

While working with WebStorm 2019.3.2, I have noticed some warnings in Angular templates: https://example.com/image.png This is happening because the properties are being initialized on the parent component instead of the child. @Component({ selector: ...