Binding CSS Styles to Events in Angular Apps
Angular allows you to conditionally define both classes and styles via the ngClass and ngStyle directives respectively. Overall, these work very well. However, there are cases when they cannot be used, for example for:
- dynamic styling of elements using TypeScript variables that are not known before execution, or
- assigning styles to pseudo-classes such as focus and hover.
The techniques will be demonstrated using an application that transmits the colors of the theme to a component via @Grab settings. These will be used to define the context, float, and to concentrate border colors.
Demo application
Here is a screenshot of the demo app that shows the three colors that can be set dynamically via the input fields:
Each color is indicated in a square above the form for reference. Below the form you will find an SVG of the famous Twitter logo. We can see the selected hover color when the cursor is placed over the image:
Tabbing on the image changes the border to the color of the selected focus border color:
Of the three colors, only the background can be set using an Angular directive; the other two require a different solution, like the ones below.
Technique # 1: CSS Variables
You may be familiar with Less and Sass variables which are compiled in pure CSS before use. Now there are “pure” CSS variables. These are defined by prefixing a double hyphen (-) before the name of the variable. Then, to access the value of a CSS variable, we would pass it to the var () function. Our application declares three of these variables – one for each color definition:
These are used to define the three preview squares in the AppComponent.
$backgroundColor: var(--background-color); $hoverColor: var(--hover-color); $focusBorderColor: var(--focus-border-color);
These variables are applied to CSS rules as follows:
.background { background-color: $backgroundColor; } .hover-background { background-color: $hoverColor; } .focus-border-background { background-color: $focusBorderColor; }
If the var () the function looks familiar, it’s by design. It is named after the JavaScript (JS) variable declaration keyword. This is because we can reference (and modify!) CSS variables from our JS code, or, in the case of Angular applications, in TypeScript. .ts component files. Here is the function that assigns three JS variables to the above CSS variables that we declared earlier:
public setColors(background: string, hover: string, focus: string) { const docStyle = document.documentElement.style; docStyle.setProperty('-- background-color', background); docStyle.setProperty('--hover- color', hover); docStyle.setProperty('--focus- border-color', focus); }
The setColors () function is linked to the click event of the APPLY button. Each input field ngModel variable is passed as a function parameter:
>
Although not part of the demo, it should be noted that CSS variables are also applicable to pseudo-classes since the stylesheet has access to the variables:
.news-image: hover { background-color: $hoverColor; }
Technique n ° 2: define styles by programming
All HTML elements expose a style property, which allows us to define just about any style directly, without any reference to the stylesheet. In the stream component, there are two similar methods for setting the styles of SVG elements: one for the background color and another for the focus border:
public setHoverColor(event: MouseEvent) { const newsImage: HTMLDivElement =event.target; if (event.type === 'mouseenter') { newsImage.style. backgroundColor = this.hoverBackgroundColor; } else if (event.type === 'mouseleave') { newsImage.style. backgroundColor = this.backgroundColor; } }
public setFocusStyle(event: FocusEvent) { const newsImage: HTMLDivElement =event.target; if (event.type === 'focus') { newsImage.style.outline = "2px solid " + this.focusBorderColor; } else if (event.type === 'blur') { newsImage.style.outline = "none"; } }
The member variables of the above class can be defined via @Grab settings; otherwise, they keep their default values:
export class FeedComponent { @Input('background-color') backgroundColor: string = 'rgb(82, 172, 240)'; @Input('hover-background-color') hoverBackgroundColor="cyan"; @Input('focus-border-color') focusBorderColor="#CCCCCC"; }
Each type of event checked in both functions corresponds to a linked event on the news-image element. In all cases, the $ event is passed to the function in order to get the type and target of the event:
backgroundColor" (mouseenter)="setHoverColor($event)" (mouseleave)="setHoverColor($ event)" (focus)="setFocusStyle($event) " (blur)="setFocusStyle($event)" > Pass colors to the flow component
In order to trigger color updates on the APPLY button click event (as opposed to immediately), three additional variables are used. These are defined at the same time as the CSS variables in setColors ():
backgroundColorInput: string = 'rgb(82, 172, 240)'; hoverColorInput: string = 'blue'; focusBorderColorInput: string = 'darkgray'; public setColors(background: string, hover: string, focus: string) { const docStyle = document.documentElement.style; docStyle.setProperty('-- background-color', background); this.backgroundColorInput = background; docStyle.setProperty('--hover- color', hover); this.hoverColorInput = hover; docStyle.setProperty('--focus- border-color', focus); this.focusBorderColorInput = focus; } In this way, the input variables of the flow component are linked to the new variables and not to those of the text fields’ ngModels:
backgroundColorInput" [hover-background-color]=" hoverColorInput" [focus-border-color]=" focusBorderColorInput" > Don’t forget to check out the demo on stackblitz.
Read more CSS and web design tutorials.
Conclusion
In this tutorial, we learned two techniques for dynamically styling elements where the ngClass and ngStyle directives will not work. In the next article, we’ll learn how to apply CSS variables to specific elements.