Red Green Repeat Adventures of a Spec Driven Junkie

Learning Angular - Directives: ngStyle

I am continuing my journey in the Angular framework and figuring out how to work with CSS styles better given what I have learned already.

I will show/hide items using CSS style attribute visibility based on a value in the component.

Angular has certain tools designed to work with CSS styles.

This article will take you five minutes to read.

Charles James - Butterfly source and more information

Introduction

I want to extend my knowledge of Property Bindings and use them to show/hide items, like a picture of a dog!

Let’s follow the same format as before, processing an input field, if the input field has the matching value, show a picture of a dog, otherwise, show nothing.

To show/hide, I will use the CSS Style: visibility and use what I know display:

Dog by Angel Luciano

source

Following Along

If you would like to follow along with this code, you can use the Github link to get a final copy of the code or view the project in your browser using this StackBlitz link.

Basic CSS

Let’s make sure I know I have the syntax working properly for visibility and solve the problem with just CSS:

Showing an image:

<img style="visibility: visible"
	 src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">

The result: visibility: visible

To hide the image:

<img style="visibility: hidden"
	 src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">

The result: visiblity: hidden

Changing visibility from Component?

How can we convert this to be more dynamic, to have the component control visibility value?

Let’s use the first technique, string interpolation:

<img style="visibility: {\{ showDog }\}"
	 src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">

Where showDog is in the component:

export class AppComponent {
	showDog = 'visible';
}

Let’s try that and see the result:

showDog=visible; dog showing

Oh - it shows. Cool, let’s set showDog to hidden and see the result:

showDog=hidden; but it's visible

Huh? This should be “hidden”, why is this showing up?

Looking at the inspector for this section, this is the HTML:

<img _ngcontent-lgq-c0="" src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1" style="">

The fact style="" means the string interpolation does not work here. Changing showDog will not change the image visibility.

Property Bindings to the rescue?

Let’s use what we learned from the last article: Property Bindings!

<img [visibility]="showDog"
	 src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">

The result:

blank screen

Hmmm - there’s nothing displayed, this is not good. Time to check the console:

Uncaught Error: Template parse errors:
Can't bind to 'visibility' since it isn't a known property of 'p'. ("
</p>

Ooooh - that’s weird. This approach worked for disabled, why not for visibility?

Let’s try one more thing: bind to the property style, because style sets visibility:

<img [style]="visibility: showDog"
	 src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">

blank screen

Nope, nothing here either. What does the console error have this time?

Uncaught Error: Quotes are not supported for evaluation!
		Statement:  showDog located at ng:///AppModule/AppComponent.html@0:14
	at _AstToIrVisitor.visitQuote (compiler.js:7646)

Hmmm - something tells me my approach is wrong here.

Difference

  • visibility is an attribute on a CSS style, to use it, visibility attribute is part of style= method. It’s defined as a CSS property - (so why can’t property bindings work?! :-) )
  • disabled is an CSS pseudo-class where it is an attribute on the element and style.

Web development is confusing!

Back to Documentation

Well, terminology doesn’t line up, let’s go back to Angular’s documentation to see if there’s a hint.

Searching in the documentation for “style”, as we want to see what tools are there to manage CSS styles:

An attribute directive that updates styles for the containing HTML
element. Sets one or more style properties, specified as
colon-separated key-value pairs. The key is a style name, with an
optional .<unit> suffix (such as 'top.px', 'font-style.em'). The value
is an expression to be evaluated. The resulting non-null value,
expressed in the given unit, is assigned to the given style
property. If the result of evaluation is null, the corresponding style
is removed.

source

💡‼️

Let’s try using this straight up with showDog=hidden:

<img [ngStyle]="{ visibility: showDog }"
	 src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">

And the result with showDog=hidden:

showDog=hidden; image hidden

Setting showDog=visible result:

showDog=visible; image visible

Cool. Hidden hides the image, visible displays the image. Exactly what we want.

NgStyle controls CSS styles. The last approach of setting style was on the right track!

Styles, styles, styles!

When there are more styles, say: colors, background colors, etc.

<img [ngStyle]="{ visibility: showDog, background-color: backgroundColor, font-size: fontSize, font: font }"
	 src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">

Can get a bit tedious setting it inside the template. The component class can set all of the styles at once using NgStyle.

export class AppComponent {
	visibility = 'visible';
	backgroundColor = 'blue';
	dogStyle = {
		'visibility': this.visibility,
		'background-color': this.backgroundColor
	}
}

To me, this is a win as the component is manipulating all styles instead of writing it out in the element, layering in functionality.

Conclusion

Trying to use Angular’s string interpolation {\{}\} methods for styles might have worked, if I always wanted something to be visible.

Using property binding was worse, nothing displayed on screen when using it as is on the visibility property. Using property binding with style is on the right track, no success.

The ngStyle directive is a better designed solution for manipulating styles than manually working with the template. One can manipulate them however they want in code, a real win in managing complexity.