ngClass
- when to use it?Most of the styles that we need to apply are always present, and can be simply be applied as standard HTML in our templates, like this:
<p>A Bootstrap Primary Button:</p> <button class="btn btn-primary">Button</button>
But there are often styles that are applied conditionally to our templates - they are added to an element only if a certain programmatic condition is met.
This is, for example, the case of state styles (if we adopt the SMACSS terminology).
ngClass
needed?Note that many state styles can be natively implemented using browser CSS pseudo-classes, such as for example:
:focus
pseudo class:hover
and :active
)For these type of state styles natively supported by the browser, it's better to use the CSS pseudo classes whenever possible. So for these very common cases we won't need ngClass
.
ngClass
But there are many other state styles that are not natively supported by the browser. These styles could for example include:
If the element that we are styling only has one of those state styles, we can even apply it simply by using the plain input property template syntax, without any extra directive:
<p>Default Button:</p> <button class="btn btn-primary" type="submit">Button</button> <p>Equivalent example using Button:</p> <button class="btn" [class.btn-primary]="true" type="submit">Button</button>
Notice the syntax [class.btn-primary]
that is activating the btn-primary
CSS class, effectively adding it to the button.
This expression will add or not the class to the element depending on the truthiness of the expression, which in this case is always true.
But more often than not, an element ends up having multiple state styles, and that is when the ngClass
directive comes in handy!
The ngClass
directive will take an expression that will be used to determine which state styles to apply at a given time to the styled element.
The expression passed on to ngClass
can be:
Let's go over each one of these 3 cases with examples, and then see how we can make sure that we can still keep our templates light and readable.
ngClass
One way of defining what classes should be active at a given moment is to pass an array of strings to the ngClass
directive.
For example, the following expression contains an array of classes:
<p>Passing an Array of classes:</p> <button [ngClass]="['btn', 'btn-primary']">Button</button>
Angular will then take the array passed to ngClass
, and apply the CSS classes that it contains to the HTML button element. This is the resulting HTML:
<button class="btn btn-primary">Button</button>
Notice that the CSS classes don't have to be hard-coded in the template using this syntax (its just an example), more on this later.
ngClass
Its also possible to pass to ngClass
a string, that contains all the CSS classes that we want to apply to a given element:
<p>Passing a string:</p> <button [ngClass]="'btn btn-primary'" type="submit" (click)="submit()">Button</button>
This syntax would give the same results as before, meaning that the two CSS classes btn
and btn-primary
would still be applied.
ngClass
The last and most commonly used way that we can configure ngClass
is by passing it an object:
Let's have a look at an example of how to use this syntax:
<p>Passing a configuration object:</p><button [ngClass]="{ btn:true, 'btn-primary':true }"> Button</button>
This example would give the same results as before: the two CSS classes would still get applied.
But if for example start using longer expressions to calculate our boolean values, or have several state classes, this syntax could quickly become hard to read, overloading the template and putting too much logic in it.
Let's then see what we can if we run into that case!
One of the roles of the component class is to:
If our ngClass
expressions start to get too cumbersome and hard to read, what we can do is pass to ngClass
the output of a component method:
@Component({selector: 'app-root',template: `<button (click)="toggleState()">Toggle State</button> <p>Obtaining the CSS classes from the component method:</p> <button [ngClass]="calculateClasses()" (click)="submit()">Button</button> `})export class AppComponent { stateFlag = false; toggleState() {this.stateFlag = !this.stateFlag; } submit() {console.log('Button submitted'); } calculateClasses() { return {btn: true, 'btn-primary': true, 'btn-extra-class': this.stateFlag }; }}
Notice that we could pass parameters to this method if needed. Let's then break down what is going on in this example:
stateFlag
, which will identify if a given component state is active or not.enum
, or a calculation derived from the input datacalculateClasses
will now return a configuration object equivalent to the one we just saw abovebtn-extra-class
will be added or not to the HTML button depending on the value of the stateFlag
variableBut this time around the calculation of the configuration object is done in a component method, and the template becomes a bit more readable.
This function could have also returned an array or string containing multiple CSS classes, and the example would still work!
As we can see, between the native browser functionality and ngClass
, we will be able to do most of the styling for our components.
But are there use cases where we would like to apply styles directly to an element?
ngStyle
to add embedded styles to our templatesJust like in the case of plain CSS, sometimes there are valid use cases for applying directly styles to an HTML element, although in general this is to be avoided.
This is because this type of embedded styles takes precedence over any CSS styles except styles that are marked with !important
.
To give an example of when we would like to use this: Imagine a color picker element, that sets the color of a sample rectangle based on a handle that gets dragged by the user.
The varying color of the element needs an embedded HTML style, as its not known upfront. If we run into such an use case using Angular, we can implement it using the ngStyle
built-in core directive:
<p>Passing an object to ngStyle:</p><button [ngStyle]="{background: 'red'}">Button</button>
And this would be the resulting HTML:
<button style="background: red">Button</button>
Just like the case of ngClass
, if our ngStyle
expression starts to get too large, we can always call a component method to calculate the configuration object:
<p>Obtaining styles from a component method:</p><button [ngStyle]="calculateStyles()">Button</button>
And with this, we can now add both CSS classes and embedded styles conditionally to our components!