Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Angular Cookbook
Angular Cookbook

Angular Cookbook: Over 80 actionable recipes every Angular developer should know

eBook
€15.99 €23.99
Paperback
€29.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Angular Cookbook

Chapter 2: Understanding and Using Angular Directives

In this chapter, you'll learn about Angular directives in depth. You'll learn about attribute directives, with a really good real-world example of using a highlight directive. You'll also write your first structural directive and see how ViewContainer and TemplateRef services work together to add/remove elements from the Document Object Model (DOM), just as in the case of *ngIf, and you'll create some really cool attribute directives that do different tasks. Finally, you'll learn how to use multiple structural directives on the same HyperText Markup Language (HTML) element and how to enhance template type checking for your custom directives.

Here are the recipes we're going to cover in this chapter:

  • Using attribute directives to handle the appearance of elements
  • Creating a directive to calculate the read time for articles
  • Creating a basic directive that allows you to vertically scroll to an element
  • Writing your first custom structural directive
  • How to use *ngIf and *ngSwitch together
  • Enhancing template type checking for your custom directives

Technical requirements

For the recipes in this chapter, make sure you have Git and Node.js installed on your machine. You also need to have the @angular/cli package installed, which you can do with npm install -g @angular/cli from your terminal. The code for this chapter can be found at https://github.com/PacktPublishing/Angular-Cookbook/tree/master/chapter02.

Using attribute directives to handle the appearance of elements

In this recipe, you'll work with an Angular attribute directive named highlight. With this directive, you'll be able to search words and phrases within a paragraph and highlight them on the go. The whole paragraph's container background will also be changed when we have a search in action.

Getting ready

The project we are going to work with resides in chapter02/start_here/ad-attribute-directive, inside the cloned repository:

  1. Open the project in Visual Studio Code (VS Code).
  2. Open the terminal, and run npm install to install the dependencies of the project.
  3. Once done, run ng serve -o.

    This should open the app in a new browser tab, and you should see something like this:

Figure 2.1 – ad-attribute-directives app running on http://localhost:4200

Figure 2.1 – ad-attribute-directives app running on http://localhost:4200

How to do it…

So far, the app has a search input box and a paragraph text. We need to be able to type a search query into the search box so that we can highlight the matching text in the paragraph. Here are the steps on how we achieve this:

  1. We'll create a property named searchText in the app.component.ts file that we'll use as a model for the search-text input:
    ...
    export class AppComponent {
      title = 'ad-attribute-directive';
      searchText = '';
    }
  2. Then, we use this searchText property in the app.component.html file with the search input as a ngModel, as follows:
    …
    <div class="content" role="main">
      ...
        <input [(ngModel)]="searchText" type="text"     class="form-control" placeholder="Search Text"     aria-label="Username" aria-describedby=    "basic-addon1">
      </div>

    Important note

    Notice that ngModel doesn't work without FormsModule, and so we've already imported FormsModule into our app.module.ts file.

  3. Now, we'll create an attribute directive named highlight by using the following command inside our ad-attributes-directive project:
     ng g d directives/highlight
  4. The preceding command generated a directive that has a selector called appHighlight. See the How it works… section for why that happens. Now that we have the directive in place, we'll create two inputs for the directive to be passed from AppComponent (from app.component.html)—one for the search text and another for the highlight color. The code should look like this in the highlight.directive.ts file:
     import { Directive, Input } from '@angular/core';
    @Directive({
      selector: '[appHighlight]'
    })
    export class HighlightDirective {
      @Input() highlightText = '';
      @Input() highlightColor = 'yellow';
      constructor() { }
    }
  5. Since we have the inputs in place now, let's use the appHighlight directive in app.component.html and pass the searchText model from there to the appHighlight directive:
    <div class="content" role="main">
      ...
      <p class="text-content" appHighlight   [highlightText]="searchText">
        ...
      </p>
    </div>
  6. We'll listen to the input changes now for the searchText input, using ngOnChanges. Please see the Using ngOnChanges to intercept input property changes recipe in Chapter 1, Winning Components Communication, for how to listen to input changes. For now, we'll only do a console.log when the input changes:
    import { Directive, Input, SimpleChanges, OnChanges } from '@angular/core';
    @Directive({
      selector: '[appHighlight]'
    })
    export class HighlightDirective implements OnChanges {
      ...
      ngOnChanges(changes: SimpleChanges) {
        if (changes.highlightText.firstChange) {
          return;
        }
        const { currentValue } = changes.highlightText;
        console.log(currentValue);
      }
    }
  7. Now, we'll write some logic for what to do when we actually have something to search for. For this, we'll first import the ElementRef service so that we can get access to the template element on which our directive is applied. Here's how we'll do this:
    import { Directive, Input, SimpleChanges, OnChanges, ElementRef } from '@angular/core';
    @Directive({
      selector: '[appHighlight]'
    })
    export class HighlightDirective implements OnChanges {
      @Input() highlightText = '';
      @Input() highlightColor = 'yellow';
      constructor(private el: ElementRef) { }
      ...
    }
  8. Now, we'll replace every matching text in our el element with a custom <span> tag with some hardcoded styles. Update your ngOnChanges code in highlight.directive.ts as follows, and see the result:
    ngOnChanges(changes: SimpleChanges) {
        if (changes.highlightText.firstChange) {
          return;
        }
        const { currentValue } = changes.highlightText;
        if (currentValue) {
          const regExp = new RegExp(`(${currentValue})`,       'gi')
          this.el.nativeElement.innerHTML =       this.el.nativeElement.innerHTML.replace       (regExp, `<span style="background-color:       ${this.highlightColor}">\$1</span>`)
        }
     }

    Tip

    You'll notice that if you type a word, it will still just show only one letter highlighted. That's because whenever we replace the innerHTML property, we end up changing the original text. Let's fix that in the next step.

  9. To keep the original text intact, let's create a property name of originalHTML and assign an initial value to it on the first change. We'll also use the originalHTML property while replacing the values:
    ...
    export class HighlightDirective implements OnChanges {
      @Input() highlightText = '';
      @Input() highlightColor = 'yellow';
      originalHTML = '';
      constructor(private el: ElementRef) { }
      ngOnChanges(changes: SimpleChanges) {
        if (changes.highlightText.firstChange) {
          this.originalHTML = this.el.nativeElement.      innerHTML;
          return;
        }
        const { currentValue } = changes.highlightText;
        if (currentValue) {
          const regExp = new RegExp(`(${currentValue})`,       'gi')
          this.el.nativeElement.innerHTML =       this.originalHTML.replace(regExp, `<span       style="background-color: ${this.      highlightColor}">\$1</span>`)
        }
      }
    }
  10. Now, we'll write some logic to reset everything back to the originalHTML property when we remove our search query (when the search text is empty). In order to do so, let's add an else condition, as follows:
    ...
    export class HighlightDirective implements OnChanges {
      ...
      ngOnChanges(changes: SimpleChanges) {
       ...
        if (currentValue) {
          const regExp = new RegExp(`(${currentValue})`,       'gi')
          this.el.nativeElement.innerHTML = this.      originalHTML.replace(regExp, `<span       style="background-color: ${this.      highlightColor}">\$1</span>`)
        } else {
          this.el.nativeElement.innerHTML =       this.originalHTML;
        }
      }
    }

How it works…

We create an attribute directive that takes the highlightText and highlightColor inputs and then listens to the input changes for the highlightText input using the SimpleChanges application programming interface (API) and the ngOnChanges life cycle hook.

First, we make sure to save the original content of the target element by getting the attached element using the ElementRef service, using the .nativeElement.innerHTML on the element, and then saving it to originalHTML property of the directive. Then, whenever the input changes, we replace the text with an additional HTML element (a <span> element) and add the background color to this span element. We then replace the innerHTML property of the target element with this modified version of the content. That's all the magic!

See also

Creating a directive to calculate the read time for articles

In this recipe, you'll create an attribute directive to calculate the read time of an article, just like Medium. The code for this recipe is highly inspired by my existing repository on GitHub, which you can view at the following link: https://github.com/AhsanAyaz/ngx-read-time.

Getting ready

The project for this recipe resides in chapter02/start_here/ng-read-time-directive:

  1. Open the project in VS Code.
  2. Open the terminal, and run npm install to install the dependencies of the project.
  3. Once done, run ng serve -o.

    This should open the app in a new browser tab, and you should see something like this:

Figure 2.2 – ng-read-time-directive app running on http://localhost:4200

Figure 2.2 – ng-read-time-directive app running on http://localhost:4200

How to do it…

Right now, we have a paragraph in our app.component.html file for which we need to calculate the read time in minutes. Let's get started:

  1. First, we'll create an attribute directive named read-time. To do that, run the following command:
    ng g directive directives/read-time
  2. The preceding command created an appReadTime directive. We'll first apply this directive to div inside the app.component.html file with the id property set to mainContent, as follows:
    ...
    <div class="content" role="main" id="mainContent" appReadTime>
    ...
    </div>
  3. Now, we'll create a configuration object for our appReadTime directive. This configuration will contain a wordsPerMinute value, on the basis of which we'll calculate the read time. Let's create an input inside the read-time.directive.ts file with a ReadTimeConfig exported interface for the configuration, as follows:
    import { Directive, Input } from '@angular/core';
    export interface ReadTimeConfig {
      wordsPerMinute: number;
    }
    @Directive({
      selector: '[appReadTime]'
    })
    export class ReadTimeDirective {
      @Input() configuration: ReadTimeConfig = {
        wordsPerMinute: 200
      }
      constructor() { }
    }
  4. We can now move on to getting the text to calculate the read time. For this, we'll use the ElementRef service to retrieve the textContent property of the element. We'll extract the textContent property and assign it to a local variable named text in the ngOnInit life cycle hook, as follows:
    import { Directive, Input, ElementRef, OnInit } from '@angular/core';
    ...
    export class ReadTimeDirective implements OnInit {
      @Input() configuration: ReadTimeConfig = {
        wordsPerMinute: 200
      }
      constructor(private el: ElementRef) { }
      ngOnInit() {
        const text = this.el.nativeElement.textContent;
      }
    }
  5. Now that we have our text variable filled up with the element's entire text content, we can calculate the time to read this text. For this, we'll create a method named calculateReadTime by passing the text property to it, as follows:
    ...
    export class ReadTimeDirective implements OnInit {
      ...
      ngOnInit() {
        const text = this.el.nativeElement.textContent;
        const time = this.calculateReadTime(text);
      }
      calculateReadTime(text: string) {
        const wordsCount = text.split(/\s+/g).length;
        const minutes = wordsCount / this.configuration.    wordsPerMinute;
        return Math.ceil(minutes);
      }
    }
  6. We've got the time now in minutes, but it's not in a user-readable format at the moment since it is just a number. We need to show it in a way that is understandable for the end user. To do so, we'll do some minor calculations and create an appropriate string to show on the user interface (UI). The code is shown here:
    ...
    @Directive({
      selector: '[appReadTime]'
    })
    export class ReadTimeDirective implements OnInit {
    ...
      ngOnInit() {
        const text = this.el.nativeElement.textContent;
        const time = this.calculateReadTime(text);
        const timeStr = this.createTimeString(time);
        console.log(timeStr);
      }
    ...
      createTimeString(timeInMinutes) {
        if (timeInMinutes === 1) {
          return '1 minute';
        } else if (timeInMinutes < 1) {
          return '< 1 minute';
        } else {
          return `${timeInMinutes} minutes`;
        }
      }
    }

    Note that with the code so far, you should be able to see the minutes on the console when you refresh the application.

  7. Now, let's add an @Output() to the directive so that we can get the read time in the parent component and display it on the UI. Let's add it as follows in the read-time.directive.ts file:
    import { Directive, Input, ElementRef, OnInit, Output, EventEmitter } from '@angular/core';
    ...
    export class ReadTimeDirective implements OnInit {
      @Input() configuration: ReadTimeConfig = {
        wordsPerMinute: 200
      }
      @Output() readTimeCalculated = new   EventEmitter<string>();
      constructor(private el: ElementRef) { }
    ...
    }
  8. Let's use the readTimeCalculated output to emit the value of the timeStr variable from the ngOnInit() method when we've calculated the read time:
    ...
    export class ReadTimeDirective {
    ...
      ngOnInit() {
        const text = this.el.nativeElement.textContent;
        const time = this.calculateReadTime(text);
        const timeStr = this.createTimeString(time);
        this.readTimeCalculated.emit(timeStr);
      }
    ...
    }
  9. Since we emit the read-time value using the readTimeCalculated output, we have to listen to this output's event in the app.component.html file and assign it to a property of the AppComponent class so that we can show this on the view. But before that, we'll create a local property in the app.component.ts file to store the output event's value, and we'll also create a method to be called upon when the output event is triggered. The code is shown here:
    ...
    export class AppComponent {
      readTime: string;
      onReadTimeCalculated(readTimeStr: string) {
        this.readTime = readTimeStr;
      } 
    }
  10. We can now listen to the output event in the app.component.html file, and we can then call the onReadTimeCalculated method when the readTimeCalculated output event is triggered:
    ...
    <div class="content" role="main" id="mainContent" appReadTime (readTimeCalculated)="onReadTimeCalculated($event)">
    ...
    </div>
  11. Now, we can finally show the read time in the app.component.html file, as follows:
    <div class="content" role="main" id="mainContent" appReadTime (readTimeCalculated)="onReadTimeCalculated($event)">
      <h4>Read time = {{readTime}}</h4>
      <p class="text-content">
        Silent sir say desire fat him letter. Whatever     settling goodness too and honoured she building     answered her. ...
      </p>
    ...
    </div>

How it works…

The appReadTime directive is at the heart of this recipe. We use the ElementRef service inside the directive to get the native element that the directive is attached to, then we take out its text content. The only thing that remains then is to perform the calculation. We first split the entire text content into words by using the /\s+/g regular expression (regex), and thus we count the total words in the text content. Then, we divide the word count by the wordsPerMinute value we have in the configuration to calculate how many minutes it would take to read the entire text. Easy peasy, lemon squeezy.

See also

Creating a basic directive that allows you to vertically scroll to an element

In this recipe, you'll create a directive to allow the user to scroll to a particular element on the page, on click.

Getting ready

The project for this recipe resides in chapter02/start_here/ng-scroll-to-directive:

  1. Open the project in VS Code.
  2. Open the terminal, and run npm install to install the dependencies of the project.
  3. Once done, run ng serve -o.

    This should open the app in a new browser tab, and you should see something like this:

Figure 2.3 – ng-scroll-to-directive app running on http://localhost:4200

Figure 2.3 – ng-scroll-to-directive app running on http://localhost:4200

How to do it…

  1. First off, we'll create a scroll-to directive so that we can enhance our application with smooth scrolls to different sections. We'll do this using the following command in the project:
    ng g directive directives/scroll-to
  2. Now, we need to make the directive capable of accepting an @Input() that'll contain the Cascading Style Sheets (CSS) Query Selector for our target section that we'll scroll to upon the element's click event. Let's add the input as follows to our scroll-to.directive.ts file:
    import { Directive, Input } from '@angular/core';
    @Directive({
      selector: '[appScrollTo]'
    })
    export class ScrollToDirective {
      @Input() target = '';
      constructor() { }
    }
  3. Now, we'll apply the appScrollTo directive to the links in the app.component.html file along with the respective targets so that we can implement the scroll logic in the next steps. The code should look like this:
    ...
    <div class="content" role="main">
      <div class="page-links">
        <h4 class="page-links__heading">
          Links
        </h4>
        <a class="page-links__link" appScrollTo     target="#resources">Resources</a>
        <a class="page-links__link" appScrollTo     target="#nextSteps">Next Steps</a>
        <a class="page-links__link" appScrollTo     target="#moreContent">More Content</a>
        <a class="page-links__link" appScrollTo     target="#furtherContent">Further Content</a>
        <a class="page-links__link" appScrollTo     target="#moreToRead">More To Read</a>
      </div>
      ...
      <div class="to-top-button">
        <a appScrollTo target="#toolbar" class=    "material-icons">
          keyboard_arrow_up
        </a>
      </div>
    </div>
  4. Now, we'll implement the HostListener() decorator to bind the click event to the element the directive is attached to. We'll just log the target input when we click the links. Let's implement this, and then you can try clicking on the links to see the value of the target input on the console:
    import { Directive, Input, HostListener } from '@angular/core';
    @Directive({
      selector: '[appScrollTo]'
    })
    export class ScrollToDirective {
      @Input() target = '';
      @HostListener('click')
      onClick() {
        console.log(this.target);
      }
      ...
    }
  5. Since we have the click handler set up already, we can now implement the logic to scroll to a particular target. For that, we'll use the document.querySelector method, using the target variable's value to get the element, and then the Element.scrollIntoView() web API to scroll the target element. With this change, you should have the page being scrolled to the target element already when you click the corresponding link:
    ...
    export class ScrollToDirective {
      @Input() target = '';
      @HostListener('click')
      onClick() {
        const targetElement = document.querySelector     (this.target);
        targetElement.scrollIntoView();
      }
      ...
    }
  6. All right—we got the scroll working. "But what's new, Ahsan? Isn't this exactly what we were already doing with the href implementation before?" Well, you're right. But, we're going to make the scroll super smoooooth. We'll pass scrollIntoViewOptions as an argument to the scrollIntoView method with the {behavior: "smooth"} value to use an animation during the scroll. The code should look like this:
    ...
    export class ScrollToDirective {
      @Input() target = '';
      @HostListener('click')
      onClick() {
        const targetElement = document.querySelector     (this.target);
        targetElement.scrollIntoView({behavior: 'smooth'});
      }
      constructor() { }
    }

How it works…

The essence of this recipe is the web API that we're using within an Angular directive, and that is Element.scrollIntoView(). We first attach our appScrollTo directive to the elements that should trigger scrolling upon clicking them. We also specify which element to scroll to by using the target input for each directive attached. Then, we implement the click handler inside the directive with the scrollIntoView() method to scroll to a particular target, and to use a smooth animation while scrolling, we pass the {behavior: 'smooth'} object as an argument to the scrollIntoView() method.

There's more…

Writing your first custom structural directive

In this recipe, you'll write your first custom structural directive named *appIfNot that will do the opposite of what *ngIf does—that is, you'll provide a Boolean value to the directive, and it will show the content attached to the directive when the value is false, as opposed to how the *ngIf directive shows the content when the value provided is true.

Getting ready

The project for this recipe resides in chapter02/start_here/ng-if-not-directive:

  1. Open the project in VS Code.
  2. Open the terminal, and run npm install to install the dependencies of the project.
  3. Once done, run ng serve -o.

    This should open the app in a new browser tab, and you should see something like this:

Figure 2.4 – ng-if-not-directive app running on http://localhost:4200

Figure 2.4 – ng-if-not-directive app running on http://localhost:4200

How to do it…

  1. First of all, we'll create a directive using the following command in the project root:
    ng g directive directives/if-not
  2. Now, instead of the *ngIf directive in the app.component.html file, we can use our *appIfNot directive. We'll also reverse the condition from visibility === VISIBILITY.Off to visibility === VISIBILITY.On, as follows:
    ...
    <div class="content" role="main">
      ...
      <div class="page-section" id="resources"   *appIfNot="visibility === VISIBILITY.On">
        <!-- Resources -->
        <h2>Content to show when visibility is off</h2>
      </div>
    </div>
  3. Now that we have set the condition, we need to create an @Input inside the *appIfNot directive that accepts a Boolean value. We'll use a setter to intercept the value changes and will log the value on the console for now:
    import { Directive, Input } from '@angular/core';
    @Directive({
      selector: '[appIfNot]'
    })
    export class IfNotDirective {
      constructor() { }
      @Input() set appIfNot(value: boolean) {
        console.log(`appIfNot value is ${value}`);
      }
    }
  4. If you tap on the Visibility On and Visibility Off buttons now, you should see the values being changed and reflected on the console, as follows:
    Figure 2.5 – Console logs displaying changes for the appIfNot directive values

    Figure 2.5 – Console logs displaying changes for the appIfNot directive values

  5. Now, we're moving toward the actual implementation of showing and hiding the content based on the value being false and true respectively, and for that, we first need the TemplateRef service and the ViewContainerRef service injected into the constructor of if-not.directive.ts. Let's add these, as follows:
    import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
    @Directive({
      selector: '[appIfNot]'
    })
    export class IfNotDirective {
      constructor(private templateRef: TemplateRef<any>,   private viewContainerRef: ViewContainerRef) { }
      @Input() set appIfNot(value: boolean) {
        console.log(`appIfNot value is ${value}`);
      }
    }
  6. Finally, we can add the logic to add/remove the content from the DOM based on the appIfNot input's value, as follows:
    ...
    export class IfNotDirective {
      constructor(private templateRef: TemplateRef<any>,   private viewContainerRef: ViewContainerRef) { }
      @Input() set appIfNot(value: boolean) {
        if (value === false) {
          this.viewContainerRef.      createEmbeddedView(this.templateRef);
        } else {
          this.viewContainerRef.clear()
        }
      }
    }

How it works…

Structural directives in Angular are special for multiple reasons. First, they allow you to manipulate DOM elements—that is, adding/removing/manipulating based on your needs. Moreover, they have this * prefix that binds to all the magic Angular does behind the scenes. As an example, *ngIf and *ngFor are both structural directives that behind the scenes work with the <ng-template> directive containing the content you bind the directive to and create the required variables/properties for you in the scope of ng-template. In the recipe, we do the same. We use the TemplateRef service to access the <ng-template> directive that Angular creates for us behind the scenes, containing the host element on which our appIfNot directive is applied. Then, based on the value provided to the directive as input, we decide whether to add the magical ng-template to the view or clear the ViewContainerRef service to remove anything inside it.

See also

How to use *ngIf and *ngSwitch together

In certain situations, you might want to use more than one structural directive on the same host—for example, a combination of *ngIf and *ngFor together. In this recipe, you'll learn how to do exactly that.

Getting ready

The project we are going to work with resides in chapter02/start_here/multi-structural-directives, inside the cloned repository:

  1. Open the project in VS Code.
  2. Open the terminal, and run npm install to install the dependencies of the project.
  3. Once done, run ng serve -o.

    This should open the app in a new browser tab, and you should see something like this:

Figure 2.6 – multi-structural-directives app running on http://localhost:4200

Figure 2.6 – multi-structural-directives app running on http://localhost:4200

Now that we have the app running, let's see the steps for this recipe in the next section.

How to do it…

  1. We'll start by moving the element with the No items in bucket. Add some fruits! text into its own <ng-template> element, and we'll give it a template variable called #bucketEmptyMessage. The code should look like this in the app.component.html file:
    …
    <div class="content" role="main">
     ...
      <div class="page-section">
        <h2>Bucket <i class="material-icons">shopping_cart     </i></h2>
        <div class="fruits">
          <div class="fruits__item" *ngFor="let item of       bucket;">
            <div class="fruits__item__title">{{item.name}}        </div>
            <div class="fruits__item__delete-icon"         (click)="deleteFromBucket(item)">
              <div class="material-icons">delete</div>
            </div>
          </div>
        </div>
      </div>
      <ng-template #bucketEmptyMessage>
        <div class="fruits__no-items-msg">
          No items in bucket. Add some fruits!
        </div>
      </ng-template>
    </div>
  2. Notice that we moved the entire div out of the .page-section div. Now, we'll use the ngIf-Else syntax to either show a bucket list or an empty bucket message based on the bucket's length. Let's modify the code, as follows:
    ...
    <div class="content" role="main">
      ...
      <div class="page-section">
        <h2>Bucket <i class="material-icons">shopping_cart     </i></h2>
        <div class="fruits">
          <div *ngIf="bucket.length > 0; else       bucketEmptyMessage" class="fruits__item"       *ngFor="let item of bucket;">
            <div class="fruits__item__title">{{item.name}}        </div>
            <div class="fruits__item__delete-icon"         (click)="deleteFromBucket(item)">
              <div class="material-icons">delete</div>
            </div>
          </div>
        </div>
      </div>
    ...
    </div>

    As soon as you save the preceding code, you'll see the application breaks, mentioning we can't use multiple template bindings on one element. This means we can't use multiple structural directives on one element:

    Figure 2.7 – Error on console, showing we can't use multiple directives on one element

    Figure 2.7 – Error on console, showing we can't use multiple directives on one element

  3. Now, as a final step, let's fix the issue by wrapping the div with *ngFor="let item of bucket;" inside an <ng-container> element and using the *ngIf directive on the <ng-container> element, as follows:
    ...
    <div class="content" role="main">
      ...
      <div class="page-section">
        <h2>Bucket <i class="material-icons">shopping_cart     </i></h2>
        <div class="fruits">
          <ng-container *ngIf="bucket.length > 0; else       bucketEmptyMessage">
            <div class="fruits__item" *ngFor="let item         of bucket;">
              <div class="fruits__item__title">{{item.          name}}</div>
              <div class="fruits__item__delete-icon"           (click)="deleteFromBucket(item)">
                <div class="material-icons">delete</div>
              </div>
            </div>
          </ng-container>
        </div>
      </div>
    </div>

How it works…

Since we can't use two structural directives on a single element, we can always use another HTML element as a parent to use the other structural directive. However, that adds another element to the DOM and might cause problems for your element hierarchy, based on your implementation. <ng-container>, however, is a magical element from Angular's core that is not added to the DOM. Instead, it just wraps the logic/condition that you apply to it, which makes it really easy for us to just add a *ngIf or *ngSwitchCase directive on top of your existing elements.

See also

Enhancing template type checking for your custom directives

In this recipe, you'll learn how to improve type checking in templates for your custom Angular directives using the static template guards that the recent versions of Angular have introduced. We'll enhance the template type checking for our appHighlight directive so that it only accepts a narrowed set of inputs.

Getting ready

The project we are going to work with resides in chapter02/start_here/enhanced-template-type-checking, inside the cloned repository:

  1. Open the project in VS Code.
  2. Open the terminal, and run npm install to install the dependencies of the project.
  3. Once done, run ng serve -o.

    This should open the app in a new browser tab, and you should see something like this:

Figure 2.8 – enhanced-template-type-checking app running on http://localhost:4200

Figure 2.8 – enhanced-template-type-checking app running on http://localhost:4200

Now that we have the app running, let's see the steps for this recipe in the next section.

How to do it…

  1. First off, we'll try to identify the problem, and that boils down to the ability to pass any string as a color to the highlightColor attribute/input for the appHighlight directive. Give it a try. Provide the '#dcdcdc' value as the input and you'll have a broken highlight color, but no errors whatsoever:
    ...
    <div class="content" role="main">
      ...
      <p class="text-content" appHighlight   [highlightColor]="'#dcdcdc'"   [highlightText]="searchText">
        ...
      </p>
    </div>
  2. Well, how do we fix it? By adding some angularCompileOptions to our tsconfig.json file. We'll do this by adding a flag named strictInputTypes as true. Stop the app server, modify the code as follows, and rerun the ng serve command to see the changes:
    {
      "compileOnSave": false,
      "compilerOptions": {
        ...
      },
      "angularCompilerOptions": {
        "strictInputTypes": true
      }
    }

    You should see something like this:

    Figure 2.9 – strictInputTypes helping with build time errors for incompatible type

    Figure 2.9 – strictInputTypes helping with build time errors for incompatible type

  3. Well, great! Angular now identifies that the provided '#dcdcdc' value is not assignable to the HighlightColor type. But what happens if someone tries to provide null as the value? Would it still be fine? The answer is no. We would still have a broken experience, but no error whatsoever. To fix this, we'll enable two flags for our angularCompilerOptionsstrictNullChecks and strictNullInputTypes:
    {
      "compileOnSave": false,
      "compilerOptions": {
        ...
      },
      "angularCompilerOptions": {
        "strictInputTypes": true,
        "strictNullChecks": true,
        "strictNullInputTypes": true
      }
    }
  4. Update the app.component.html file to provide null as the value for the [highlightColor] attribute, as follows:
    ...
    <div class="content" role="main">
      ...
      <p class="text-content" appHighlight   [highlightColor]="null" [highlightText]="searchText">
       ...
    </div>
  5. Stop the server, save the file, and rerun ng serve, and you'll see that we now have another error, as shown here:
    Figure 2.10 – Error reporting with strictNullInputTypes and strictNullChecks in action

    Figure 2.10 – Error reporting with strictNullInputTypes and strictNullChecks in action

  6. Now, instead of so many flags for even further cases, we can actually just put two flags that do all the magic for us and cover most of our applications—the strictNullChecks flag and the strictTemplates flag:
    {
      "compileOnSave": false,
      "compilerOptions": {
       ...
      },
      "angularCompilerOptions": {
        "strictNullChecks": true,
        "strictTemplates": true
      }
    }
  7. Finally, we can import the HighlightColor enum into our app.component.ts file. We will add a hColor property to the AppComponent class and will assign it a value from the HighlightColor enum, as follows:
    import { Component } from '@angular/core';
    import { HighlightColor } from './directives/highlight.directive';
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.scss']
    })
    export class AppComponent {
      searchText = '';
      hColor: HighlightColor = HighlightColor.LightCoral;
    }
  8. We'll now use the hColor property in the app.component.html file to pass it to the appHighlight directive. This should fix all the issues and make light coral the assigned highlight color for our directive:
    <div class="content" role="main">
    ...
      <p class="text-content" appHighlight   [highlightColor]="hColor" [highlightText]="searchText">
        ...
      </p>
    </div>

See also

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Explore recipes across core Angular topics to fill gaps in your knowledge of using Angular in production
  • Discover industry best practices and tooling to enhance your development experience with Angular
  • Understand advanced topics in Angular to help you become a proficient enterprise web developer

Description

The Angular framework, powered by Google, is the framework of choice for many web development projects built across varying scales. It’s known to provide much-needed stability and a rich tooling ecosystem for building production-ready web and mobile apps. This recipe-based guide enables you to learn Angular concepts in depth using a step-by-step approach. You’ll explore a wide range of recipes across key tasks in web development that will help you build high-performance apps. The book starts by taking you through core Angular concepts such as Angular components, directives, and services to get you ready for building frontend web apps. You’ll develop web components with Angular and go on to cover advanced concepts such as dynamic components loading and state management with NgRx for achieving real-time performance. Later chapters will focus on recipes for effectively testing your Angular apps to make them fail-safe, before progressing to techniques for optimizing your app’s performance. Finally, you’ll create Progressive Web Apps (PWA) with Angular to provide an intuitive experience for users. By the end of this Angular book, you’ll be able to create full-fledged, professional-looking Angular apps and have the skills you need for frontend development, which are crucial for an enterprise Angular developer.

Who is this book for?

The book is for intermediate-level Angular web developers looking for actionable solutions to common problems in Angular enterprise development. Mobile developers using Angular technologies will also find this book useful. Working experience with JavaScript and TypeScript is necessary to understand the topics covered in this book more effectively.

What you will learn

  • Gain a better understanding of how components, services, and directives work in Angular
  • Understand how to create Progressive Web Apps using Angular from scratch
  • Build rich animations and add them to your Angular apps
  • Manage your app's data reactivity using RxJS
  • Implement state management for your Angular apps with NgRx
  • Optimize the performance of your new and existing web apps
  • Write fail-safe unit tests and end-to-end tests for your web apps using Jest and Cypress
  • Get familiar with Angular CDK components for designing effective Angular components
Estimated delivery fee Deliver to Denmark

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Aug 06, 2021
Length: 652 pages
Edition : 1st
Language : English
ISBN-13 : 9781838989439
Vendor :
Google
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Denmark

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Publication date : Aug 06, 2021
Length: 652 pages
Edition : 1st
Language : English
ISBN-13 : 9781838989439
Vendor :
Google
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 95.97
TypeScript 4 Design Patterns and Best Practices
€27.99
Angular Cookbook
€29.99
Angular Projects
€37.99
Total 95.97 Stars icon
Banner background image

Table of Contents

14 Chapters
Chapter 1: Winning Components Communication Chevron down icon Chevron up icon
Chapter 2: Understanding and Using Angular Directives Chevron down icon Chevron up icon
Chapter 3: The Magic of Dependency Injection in Angular Chevron down icon Chevron up icon
Chapter 4: Understanding Angular Animations Chevron down icon Chevron up icon
Chapter 5: Angular and RxJS – Awesomeness Combined Chevron down icon Chevron up icon
Chapter 6: Reactive State Management with NgRx Chevron down icon Chevron up icon
Chapter 7: Understanding Angular Navigation and Routing Chevron down icon Chevron up icon
Chapter 8: Mastering Angular Forms Chevron down icon Chevron up icon
Chapter 9: Angular and the Angular CDK Chevron down icon Chevron up icon
Chapter 10: Writing Unit Tests in Angular with Jest Chevron down icon Chevron up icon
Chapter 11: E2E Tests in Angular with Cypress Chevron down icon Chevron up icon
Chapter 12: Performance Optimization in Angular Chevron down icon Chevron up icon
Chapter 13: Building PWAs with Angular Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.4
(14 Ratings)
5 star 64.3%
4 star 7.1%
3 star 28.6%
2 star 0%
1 star 0%
Filter icon Filter
Top Reviews

Filter reviews by




Neakjie Oct 20, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
It’s very useful for enterprise level SPA development.
Amazon Verified review Amazon
Ria Jul 17, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Wish I bought this book sooner. Right away clarifies in succinct language / effective examples mechanisms like observables and how to properly access child components.
Amazon Verified review Amazon
Pranam Bhat Sep 14, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Angular Cookbook comes up with a lot of updates and new feature's. For example, Angular Materials, State Change, etc, etc. All these core concepts explained really well. The interesting feature about this book is - It has given enough examples and elaborates each topic with it's usage. One must read this book to get hands on real world usage of core concepts of Angular.Author has core knowledge on Angular concepts and he's also a Google Developer Expert.I recommend this book to all the Angular freaks over there.
Amazon Verified review Amazon
Sahil Sep 15, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Just finished reading this book. It is nicely curated and it has recipes which will help you to understand different concepts about Angular and level your self up really fast!
Amazon Verified review Amazon
Samuel Stegall Aug 31, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Angular Cookbook is a great resource for new and experienced Angular Developers alike. What the book excels at is showing common patterns and boilerplate for intermediate and complex topics. This is the sort of book that I would turn to if I need to implement something complex that I have not implemented before, or if I need to look at a code sample for something that I do infrequently.My favorite section in the Angular Cookbook is its section on animations. Animations are a great way to provide reactivity and fluidity to a web app, but they can be somewhat daunting to write for newer Angular developers. The Angular Cookbook provides code samples for animating components, but takes it one step further by explaining how a given code sample works and what the sample is doing. Providing extra context like this is critical for newer developers to learn and fully understand what they're doing.The only thing I could see that might be improved in this book is that there are unnecessary references to VS Code in several of the Getting Started sections. This isn't a major issue: using any IDE is fine. However, since the book doesn't use any plugins, snippets, or VS Code-specific features, I don't see much of a reason why VS Code would be mentioned explicitly. A newer developer may get a bit confused by this and go out of their way to install additional software that may not be necessary if they already have an editor of choice.Overall, this is a stellar book that all Angular developers would benefit from having on their bookshelves.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact [email protected] with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at [email protected] using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on [email protected] with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on [email protected] within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on [email protected] who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on [email protected] within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela