Angular Built-in Attribute Directives
Angular directives are a great way to manipulate the DOM and add functionality and behavior to HTML elements and Angular components. You can build your own directives with every functionality you want, but Angular also offers us some great built-in directives. If you want more information about how Angular Directives work and how to create your own you can read:
Angular Directives - A Complete Step by Step Guide
Angular directives come in 2 types, attribute directives and structural directives. Attribute directives are used to manipulate the behavior or styling of DOM elements and Angular components. Structural directives are used to remove or add DOM elements and Angular components. The conditions on which the DOM is manipulated are determined in the Typescript file of the directives.
In this article, we will have a look at the most commonly used built-in attribute directives. We will be discussing the following built-in Angular directives:
Attribute Directives:
NgClass - used to add or remove CSS classes based on a condition
NgStyle - used to add or remove inline styling based on a condition
NgModel - used to add one or two-way data binding to an HTML form elements
Table of content:
Using ngClass to add and remove CSS classes
Using ngStyle to add or remove inline styling
Using ngClass to add and remove CSS classes
NgClass is a built-in Angular directive that removes or adds CSS classes based on a condition. The ngClass directive should only be used if you need to add or alternate two or more classes based on a condition. If you just want to add one CSS class based on a true or false statement you can use the class binding instead:
[class.redBackground]="someTrueOrFalseValue"
In the above example, we are using class binding to add the CSS class 'redBackground' if the value of 'someTrueOfFalseValue' evaluates to true. But now what if we want to add another CSS class 'greenBackground' if the value evaluates to false? In this case, we can use the built-in ngClass directive to alternate between the 'redBackground' and 'greenBackground' CSS classes based on the value of the 'someTrueOfFalseValue' variable. Let's see how to use ngClass with an expression to accomplish this.
As you can see to use the directive you add ngClass between square brackets and add an expression with the ternary operator next to it. If you want to add multiple classes based on the expression you can do so like this:
You can also create if-else statements in the ngClass directive with the ternary operator.
As you can imagine using the ngClass with if-else statements can become hard to read and make a mess of your HTML template. As always there is a cleaner way of doing this, so let's have a look at using the ngClass directive with a method to resolve the classes. When you use a method to resolve the classes the method needs to set a Record that is consumed by the ngClass directive.
Record<string,boolean>
Our Record is an object with an object key on the left (representing a string) and a boolean value on the right side. The object key will be added as a CSS class if the boolean assigned to it evaluates to true. The method would look something like this:
In the TypeScript file 2 methods are added, the 'setCurrentClasses()' where we set the Record that we will pass to the ngClass directive. To initialize the CSS classes we call this method inside the ngOnInit, if you do not want the classes initialized up front you can remove the method call from the ngOnInit.
There is also a method added to change the boolean values and call the 'setCurrentClasses()' method again. We cannot just change the boolean values now to change the classes of the ngClass directive, the setCurrentClasses method needs to be called again to set the Record object again and change the values on it. The updated HTML template now looks like this:
Changing to a method cleaned up the HTML template quite a bit, but added more code in the TypeScript file, so use your best judgment on what works best for your scenario.
Using ngStyle to add or remove inline styling
The ngStyle directive is similar to the ngClass directive only it's used to add inline styling instead of CSS classes. The ngStyle directive should only be used to add multiple inline styles to an HTML element if you just want to add a single inline style based on an expression you can use style binding:
<div [style.background-color]="someTrueOfFalseValue ? 'red' : 'green'"></div>
Now let's use the ngStyle directive to set multiple inline styles. Just as with the ngClass directive we can do this with an expression or method. Using an expression directly in the template works a little differently in the case of ngStyle. The ngStyle directive actually can only take in a Record object as input, so we need to construct an object with ternary operators assigned to the keys of that object:
Depending on how many inline styles you want to add this can become messy. To solve this we can use a method again as we did with the ngClass directive. The trade-off is that we need to call the method again after we changed the boolean values, so we need to create a method for that again as well. The TypeScript file would now look like this:
This would be the updated HTML file:
Again use your best judgment on what to use in your components. Expressions clutter your HTML file a bit more but do not need an extra method call to update the values after the booleans change and if you use a method there is more code needed in the TypeScript file.
Using ngModel for two-way data binding
The built-in Angular directive ngModel is a special one and can be used in two different ways. The regular attribute directives are used with square brackets like this: [ngStyle] or [ngClass]. When we use ngModel in this manner it's used for one-way data binding, meaning that the value of the input is bounded to the value of a property but not the other way around. The ngModel directive can also be used by adding the square and round brackets around the keyword: [(ngModel)]. Because of this syntax NgModel and also called 'banana in a box'.
When we use the ngModel directive in this manner it's for two-way binding between a property and an HTML form element. Meaning you can assign a property to an HTML form element and when you change the value inside the form element the property will be updated automatically in the TypeScript file; also when you update the property with a function the value inside the input will change. Let's demonstrate this with a simple example.
To use the ngModel directive we need to add the FormsModule to the app.module.ts:
Now let's add a simple property in your app.component.ts:
ngModelValue = '';
Now add this to your HTML template:
Now when you update the value inside of the input the 'ngModelValue' property will be updated as well. Now let's add a simple value to demonstrate that the input value will change when we update the 'ngModelValue' property inside the TypeScript file. In the HTML just add a div like this:
<div (click)="updateText()">click here</div>
Now add a function in your TypeScript file named 'updateText()' and inside it reassign the 'ngModelValue' property to a new (hard coded) text value. Now each time you click on the DIV the value inside the div will be updated and visa versa when you type inside the input the property is updated achieving two-way data binding.
Conclusion
Angular offers some great built-in directives to manipulate the DOM elements by adding your preferred styling to them or binding data to them. There are many Angular modules like the router and forms module that include their own directives for more custom built-in functionality. Directives are a great way to keep your code clean and make your UI more interactive for users. If you want reusable DOM manipulation it's often a good choice to use directives, if the built-in Angular directive doesn't do the trick you can build your own.