Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Angular Cookbook
Angular Cookbook

Angular Cookbook: Over 80 actionable recipes every Angular developer should know , Second Edition

eBook
$22.99 $33.99
Paperback
$41.99
Subscription
Free Trial
Renews at $19.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
Table of content icon View table of contents Preview book icon Preview Book

Angular Cookbook

Working with Angular Directives and Built-In Control Flow

In this chapter, you’ll learn about Angular directives in depth, with a real-world example of using a directive that highlights text on searching. You’ll also write your first structural directive and see how the ViewContainer and TemplateRef services work together to add/remove elements from the Document Object Model (DOM), just as in the case of *ngIf. You’ll also create some really cool attribute directives that do different tasks. Finally, you’ll learn how to use the Directive Composition API to apply multiple directives to the same element.

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 directive that allows you to vertically scroll to an element
  • Writing your first custom structural directive
  • How to apply multiple structural directives to the same element
  • Applying multiple directives to the same element using the Directive Composition API

Technical requirements

For the recipes in this chapter, ensure your setup is complete as per the 'Technical Requirements' in the 'Angular-Cookbook-2E' GitHub repository. For setup details, visit: https://github.com/PacktPublishing/Angular-Cookbook-2E/tree/main/docs/technical-requirements.md. The starter code for this chapter is located at https://github.com/PacktPublishing/Angular-Cookbook-2E/tree/main/start/apps/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. For example, by using the following code:

<p class="text-content max-w-2xl m-auto" appHighlight
  [highlightText]="'de'">
  <!--text here -->

The result will appear as an output as shown in Figure 2.1:

Figure 2.1: The result when using the highlight directive

Getting ready

The app that we are going to work with resides in start/apps/chapter02/ng-attribute-directive inside the cloned repository:

  1. Open the code repository in your code editor.
  2. Open the terminal, navigate to the code repository directory, and run the following command to serve the project:
    npm run serve ng-attribute-directive
    

    This should open the app in a new browser tab, and you should see the following:

    Figure 2.2: ng-attribute-directive app running on http://localhost:4200

How to do it…

The application has a search input and a paragraph of text. We want to be able to type a search query in the input so that we can highlight and find all the matching occurrences in the paragraph. Here are the steps to 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 {
      searchText = '';
    }
    
  2. Then, we use the searchText property in the template, i.e., in the app.component.html file, with the search input as an ngModel, as follows:
    ...
    <div class="content" role="main">
      ...
         <input [(ngModel)]="searchText" type="text"
           placeholder="Quick Search..." class="pr-4 !pl-10
           py-2">
      </div>
    
  3. You will notice that ngModel doesn’t work yet. This is because we’re missing the FormsModule in our application. Let’s import it into the app.component.ts file as follows:
    ...
    import { FormsModule } from '@angular/forms';
     @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      standalone: true,
      styleUrls: ['./app.component.scss'],
      imports: [CommonModule, RouterModule, FormsModule],
    })
    export class AppComponent {
      searchText = '';
    }
    
  4. Now, we’ll create an attribute directive named highlight by using the following command from the workspace root:
    cd start && nx g directive highlight --directory apps/chapter02/ng-attribute-directive/src/app --standalone
    

    If asked, choose the @nx/angular:directive schematics and choose the “As provided” action. The preceding command generates a standalone directive that has a selector called appHighlight. See the How it works… section for why that happens, and for a brief explanation of the standalone API.

  1. 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]',
      standalone: true
    })
    export class HighlightDirective {
      @Input() highlightText = '';
      @Input() highlightColor = 'yellow';
    }
    
  2. Let’s use the appHighlight directive in app.component.html and pass the searchText model from there to the appHighlight directive as follows:
    <div class="content" role="main">
      ...
      <p class="text-content" appHighlight   
        [highlightText]="searchText">
        ...
      </p>
    </div>
    
  3. 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 Component Communication, for how to listen to input changes. For now, we’ll only do a console.log when the input changes. Let’s update the highlight.directive.ts as follows:
    import { Directive, Input, OnChanges, SimpleChanges } from '@angular/core';
    ...
    export class HighlightDirective implements OnChanges {
      @Input() highlightText = '';
      @Input() highlightColor = 'yellow';
      ngOnChanges(changes: SimpleChanges) {
        if (changes['highlightText']?.firstChange) {
          return;
        }
        const { currentValue } = changes['highlightText'];
        console.log({ currentValue });
      }
    }
    

    If you type in the search input and see the console logs, you’ll see the new value being logged whenever you change the value.

  1. Now, we’ll write the logic for highlighting the search text. 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) { }
      ...
    }
    
  2. 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 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.

  1. To keep the original text intact, let’s create a property named 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>`)
        }
      }
    }
    
  2. 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 created an attribute directive named highlight (appHighlight) that takes two inputs: highlightText and highlightColor. The directive listens to the input changes for the highlightText input using the SimpleChanges from the ngOnChanges life cycle hook by Angular. Every property in this SimpleChanges object is a SimpleChange object that contains the following properties:

  • previousValue: any
  • currentValue: any
  • firstChange: boolean
  • isFirstChange(): boolean

First, we make sure to save the original content of the target element by getting the attached element using the ElementRef service. We get it using the .nativeElement.innerHTML property on the element we apply the directive to. We save the initial value to the originalHTML property of the directive.

Whenever the input changes, we assign a replaced version of the originalHTML by replacing all the instances of the searched term in the paragraph with an additional HTML element (a <span> element). We also add the background color to this <span> element. The background color applied comes from the highlightColor input. You can modify it to highlight using a different color. Play around and make this example your own.

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 (https://medium.com), which is a platform for sharing articles and blog posts. 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 app that we are going to work with resides in start/apps/chapter02/ng-read-time-directive inside the cloned repository:

  1. Open the code repository in your code editor.
  2. Open the terminal, navigate to the code repository directory, and run the following command to serve the project:
    npm run serve ng-read-time-directive
    

    This should open the app in a new browser tab and you should see the following:

    Figure 2.3: 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 from the project root and select the @nx/angular:directive schematics when asked:
    cd start && nx g directive read-time --directory apps/chapter02/ng-read-time-directive/src/app/directives --standalone=false
    

    If asked, choose the @nx/angular:directive schematics and choose the “As provided” action.

    Note that we’re using --standalone = false in the command. That is because we have an NgModule based application and the AppComponent is not a standalone component.

  1. The preceding command creates a directive with the class name ReadTimeDirective and has appReadTime as the selector. We’ll apply this directive to the div that has id set to mainContent inside the app.component.html file as follows:
    ...
    <div class="content" role="main" id="mainContent"
      appReadTime>
    ...
    </div>
    
  2. 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() { }
    }
    
  3. 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;
      }
    }
    
  4. 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);
        console.log({ readTime: time });
      }
      calculateReadTime(text: string) {
        const wordsCount = text.split(/\s+/g).length;
        const minutes = wordsCount / this.configuration.
          wordsPerMinute;
        return Math.ceil(minutes);
      }
    }
    

    If you look at the console now, you should see an object containing the readTime property being logged. The value of readTime is the time in minutes:

    Figure 2.4: Console log showing the time in minutes

  1. 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 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({ readTime: timeStr });
      }
    ...
      createTimeString(timeInMinutes: number) {
        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.

  1. 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) { }
    ...
    }
    
  2. 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);
      }
    ...
    }
    
  3. 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;
      }
    }
    
  4. 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>
    
  5. 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 class="text-3xl">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>
    

    If you now go to http://localhost:4200, you should be able to see the read time in the app, as shown in the following image:

    Figure 2.5: Read time being displayed in the app

How it works…

The appReadTime directive is at the heart of this recipe. While creating the directive, we create it as a non-standalone directive because the application itself is bootstrapped using an NgModule instead of a standalone AppComponent. We use the ElementRef service inside the directive to get the native element that the directive is attached to and 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. Finally, we make it readable in a better way using the createTimeString method. Easy peasy, lemon squeezy.

See also

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

Can you imagine being able to instantly jump to any place that your eyes can see? That would be awesome! Wouldn’t it? But what if we wanted our app to be able to do that? In this recipe, you’ll create a directive that the user can click to jump to specific sessions in an Angular application.

Getting ready

The app that we are going to work with resides in start/apps/chapter02/ng-scroll-to-directive inside the cloned repository:

  1. Open the code repository in your code editor.
  2. Open the terminal, navigate to the code repository directory, and run the following command to serve the project:
    npm run serve ng-scroll-to-directive
    

    This should open the app in a new browser tab, and you should see the following:

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

How to do it…

  1. First, 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 workspace root folder:
    cd start && nx g directive scroll-to --directory apps/chapter02/ng-scroll-to-directive/src/app/directives
    

    If asked, choose the @nx/angular:component schematics and choose the “As provided” action.

  1. Now, we need to make the directive capable of accepting an @Input() that’ll contain the CSS Query Selector for our target section, which 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 = '';
    }
    
  2. Now, we’ll apply the appScrollTo directive to the links in the app.component.html file along with the respective targets. We’ll replace the href attribute with the target attribute. The code should look like this:
    ...
    <main class="content" role="main">
      <div class="page-links">
        <h4 class="page-links__heading">
          Links
        </h4>
        <a class="page-links__link" appScrollTotarget=
          "#resources">Resources</a>
        <a class="page-links__link" appScrollTotarget=
          "#nextSteps">Next Steps</a>
        <a class="page-links__link" appScrollTotarget=
          "#moreContent">More Content</a>
        <a class="page-links__link" appScrollTotarget=
          "#furtherContent">Further Content</a>
        <a class="page-links__link" appScrollTotarget=
          "#moreToRead">More To Read</a>
      </div>
    </main>
      ...
    <a appScrollTo target="#toolbar" class="to-top-button w-12
      h-12 text-white flex items-center justify-center">
      <span class="material-symbols-outlined text-3xl text-
        white"> expand_less </span>
    </a>
    
  3. 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);
      }
      ...
    }
    
  4. We will now implement the logic to scroll to a particular target. 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 to the target element. With this change, you should see the page scrolling 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);
        if (!targetElement) {
           throw new Error('`target' is required.`);
        }
        targetElement.scrollIntoView();
      }
      ...
    }
    
  5. All right—we got the scroll to work. “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'});
      }
    }
    

How it works…

The essence of this recipe is the web API that we’re using within an Angular directive, which 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.

See also

Writing your first custom structural directive

In this recipe, you’ll write your first custom structural directive named showFor (or *appShowFor with the prefix). A structural directive is one that can add or remove elements from the DOM. So, with this directive, we will add the particular element to the DOM if a provided Boolean is true, and we will remove it after the specified time (provided as a number representing milliseconds).

Getting ready

The app that we are going to work with resides in start/apps/chapter02/ng-show-for-directive inside the cloned repository:

  1. Open the code repository in your code editor.
  2. Open the terminal, navigate to the code repository directory, and run the following command to serve the project:
    npm run serve ng-show-for-directive
    

    This should open the app in a new browser tab, and you should see the following:

    Figure 2.7: ng-show-for-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 workspace root folder:
    cd start && nx g directive show-for --directory apps/chapter02/ng-show-for-directive/src/app/directives --standalone=false
    

    If asked, choose the @nx/angular:component schematics and choose the “As provided” action.

  1. Now, instead of the *ngIf directive in the app.component.html file on the element with the class "dialog", we can use our *appShowFor directive:
    ...
    <main class="content" role="main">
      <button (click)="toggleDialog()">Toggle Dialog</button>
      <div class="dialog" *appShowFor="showDialog">
        <div class="dialog__heading">...</div>
        <div class="dialog__body">...</div>
      </div>
    </main>
    
  2. Now that we have set the condition, we need to create two @Input properties inside the directive’s TypeScript file, one being a boolean property and one being a number. We’ll use a setter to intercept the Boolean value’s changes and will log the value to the console for now:
    import { Directive, Input } from '@angular/core';
    @Directive({
      selector: '[appShowFor]',
    })
    export class ShowForDirective {
      @Input() duration = 1500;
      @Input() set appShowFor(value: boolean) {
        console.log({ showForValue: value });
      }
    }
    
  3. If you tap on the Toggle Dialog button now, you should see the values being changed and reflected on the console, as follows:

Figure 2.8: Console logs displaying changes for the appShowFor directive values

  1. Now, we’re moving toward the actual implementation of showing and hiding the content based on the value being false and true respectively. For that, we first need the TemplateRef service and the ViewContainerRef service injected into the constructor of the if-not.directive.ts file. Let’s add these, as follows:
    import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
    @Directive({
      selector: '[appShowFor]'
    })
    export class ShowForDirective{
      @Input() duration = 1500;
      @Input() set appShowFor(value: boolean) {
         console.log({ showForValue: value });
       }
       constructor(
         private templateRef: TemplateRef<any>,
         private viewContainerRef: ViewContainerRef
       ) {}
    }
    
  2. Now let’s show the element. We’re going to create a show method and we’ll call it when the value of the appShowFor property becomes true. The code should look as follows:
    ...
    export class ShowForDirective {
      @Input() duration = 1500;
      @Input() set appShowFor(value: boolean) {
        console.log({ showForValue: value });
        if (value) {
          this.show();
        }
      }
      show() {
        this.viewContainerRef.createEmbeddedView(
         this.templateRef
        );
      }
      constructor(...) {}
    }
    

    If you click the Toggle Dialog button now, you should be able to see the dialog as follows:

    Figure 2.9: Dialog being shown using the show method

  1. Let’s implement the logic of hiding the dialog. We’ll use an @Output() prop with an EventEmitter for this as we want the value of appShowFor that’s passed by the parent to be updated, instead of updating it within the directive. Modify the code as follows:
    import { ... , EventEmitter } from '@angular/core';
    ...
    export class ShowForDirective {
      @Input() duration = 1500;
      @Input() set appShowFor(value: boolean) {
        ...
      }
      @Output() elementHidden = new EventEmitter();
      show() {...}
      hide() {
        this.viewContainerRef.clear();
      }
      constructor(...) {}
    }
    
  2. Now that we have the hide method there, let’s call it after the duration time saved in the duration property of the directive. This is so the dialog hides after that duration. Modify the code of the show method as follows:
    show() {
      this.viewContainerRef.createEmbeddedView(
       this.templateRef
      );
      setTimeout(() => {
        this.elementHidden.emit();
      }, this.duration);
     }
    

    With this change, you’ll see that nothing happens if you click the Toggle Dialog button after the dialog is shown, i.e., it never gets hidden. For that, we need to listen to the elementHidden event emitter we just created.

  1. Let’s make the app.component.html listen to the elementHidden event listener to change the value of the showDialog property as follows:
    <div class="dialog" *appShowFor="showDialog"
      (elementHidden)="toggleDialog()">
        <div class="dialog__heading">
                I am a Dialog
        </div>
        <div class="dialog__body">
          And this is some random content
        </div>
      </div>
    

    With this change, you’ll notice that it still doesn’t work. Yep! Because we need to call the hide method when the value of showDialog passed as the appShowFor prop is set to false.

  1. Let’s call the hide method in the ShowForDirective (in the appShowFor property’s set method) when the value of appShowFor becomes false as follows:
    @Input() set appShowFor(value: boolean) {
        console.log({ showForValue: value });
        if (value) {
          this.show();
        } else {
          this.hide();
        }
      }
    

    The thing is… this still won’t work because a structural directive in Angular can’t emit values. Or even if it does, the parent element won’t be able to listen to it. The following Stack Overflow question discusses why and links to an open GitHub issue in the Angular repository as well: https://stackoverflow.com/q/44235638.

  1. To make our structural directive work, we need to get rid of the syntactic sugar it comes with. Let’s modify the app.component.html to use the directive in a different (expanded) way, as follows:
    <main class="content" role="main">
      <button (click)="toggleDialog()">Toggle Dialog</button>
      <ng-template [appShowFor]="showDialog"
        (elementHidden)="toggleDialog()">
        <div class="dialog">
          <div class="dialog__heading">
            I am a Dialog
          </div>
          <div class="dialog__body">
            And this is some random content
          </div>
        </div>
      </ng-template>
    </main>
    

    The dialog should be hidden now. Yay! But wait. Try clicking the Toggle Dialog button lots of times quickly. You’ll see that the app goes crazy. That’s because we end up having too many setTimeout functions registered.

  1. Let’s clear the setTimeout if we toggle the dialog to manually hide it. Update the code for the ShowForDirective class as follows:
    ...
    export class ShowForDirective {
      ...
      timer!: ReturnType<typeof setTimeout>;
      show() {
        this.viewContainerRef.createEmbeddedView(
          this.templateRef
        );
        this.timer = setTimeout(() => {
          this.elementHidden.emit();
        }, this.duration);
      }
      hide() {
        clearTimeout(this.timer);
        this.viewContainerRef.clear();
      }
      constructor(...) {}
    }
    

Awesome! You’ll notice that even if you click the Toggle Dialog button fast and too many times, the app behaves correctly.

How it works…

Structural directives in Angular are special for multiple reasons. First, they allow you to manipulate DOM elements—that is, not just showing and hiding but also adding and removing elements entirely from the DOM based on your needs. Moreover, they have the * prefix, which binds to all the magic Angular does behind the scenes. For example, Angular automatically provides the TemplateRef and ViewContainer for working with this directive. As an example, *ngIf and *ngFor are both structural directives that work behind the scenes with the <ng-template> directive containing the content you bind the directive to. They then create the required variables/properties for you in the scope of ng-template. In this 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 to which our appShowFor directive is applied. We use the ViewContainerRef service to add the TemplateRef to the DOM via the createEmbeddedView method.

We do this when the value of the appShowFor property becomes true. Notice that we’re intercepting the property appShowFor using a setter. We learned about this in Chapter 1, Winning Components Communication. We then use a setTimeout to automatically notify the parent component that the value passed to the appShowFor property needs to be changed to false. We do this using an @Output() emitter named elementHidden. Notice that we’re not supposed to make it false within the directive. The parent component is supposed to do it and it will automatically reflect in the directive. Our directive is supposed to react to that change and hide (or remove) the TemplateRef from the ViewContainer. You can see that we do this in the hide method using the this.viewContainerRef.clear(); statement. One of the key things to learn from this recipe is that if we use syntactic sugar, i.e., *appShowFor, in the app.component.html, we can’t listen to the elementHidden event emitter. That’s because this is a quirk of Angular - there’s an open issue on GitHub about this (check the See also section). For this to work, we removed the syntactic sugar and expanded the syntax by using a <ng-template> to wrap our dialog’s HTML in step 11. Notice that we just used [appShowFor] to pass the showDialog variable instead of *appShowFor="showDialog". And we are also listening to the elementHidden event on the <ng-template> element itself.

See also

How to apply multiple structural directives to the same element

In certain situations, you might want to use more than one structural directive on the same host or for the same element—for example, a combination of *ngIf and *ngFor together—which is not something Angular supports out of the box. The reason is that it is hard to identify which directive takes precedence over the other, and even if there was a system, I think the apps would become too complex and hard to manage. In this recipe, we will show a message conditionally using *ngIf when we have no items in the bucket. Since we’re supposed to show it conditionally and apply the for loop on the element, this is a perfect example to use for this recipe.

Getting ready

The app that we are going to work with resides in start/apps/chapter02/ng-multi-struc-directives inside the cloned repository:

  1. Open the code repository in your code editor.
  2. Open the terminal, navigate to the code repository directory, and run the following command to serve the project:
    npm run serve ng-multi-struc-directives
    

    This should open the app in a new browser tab, and you should see the following:

    Figure 2.10: ng-multi-struc-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 creating a template for the message to be shown when there are no items in the bucket. We’ll modify the app.component.html file for this as follows:
    <div class="fruits">
        ...
        <ng-template #bucketEmptyMessage>
          <div class="fruits__no-items-msg">
            No items in bucket. Add some fruits!
          </div>
        </ng-template>
    </div>
    
  2. Now we’ll try to apply the *ngIf condition to the element that renders the fruits. Let’s modify the code in the same file, as follows:
    ...
    <div class="fruits">
        <div
          class="fruits__item"
          *ngFor="let item of bucket"
          *ngIf="bucket.length > 0; else bucketEmptyMessage" >...</div>
        <ng-template #bucketEmptyMessage>...</ng-template>
      </div>
    

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

    Figure 2.11: Angular Language Service explaining we can’t use two structural directives on the same element

  1. We can fix this by moving one of the structural directives into a <ng-container> wrapper, which doesn’t create any additional HTML elements in the DOM. Let’s modify the code as follows:
    <div class="fruits">
      <ng-container *ngIf="bucket.length > 0; else
        bucketEmptyMessage">
        <div class="fruits__item" *ngFor="let item of bucket">
          ...
        </div>
      </ng-container>
      <ng-template #bucketEmptyMessage>...</ng-template>
    </div>
    

    With the change above, you should be able to see the message when there are no items in the bucket, as follows:

    Figure 2.12: The final result with *ngIf and *ngFor together

How it works…

Since we can’t use two structural directives on the same element (let’s say a button), we can always use another HTML element as a wrapper (parent) to use one of the structural directive on it, and the other structural directive on the target element (button in our case). However, that adds another element to the DOM and might cause problems for your element hierarchy or other layout behavioral issues, based on your implementation. However, <ng-container> is a magical element from Angular that is not added to the DOM. Instead, it just wraps the logic/condition that you apply to it, which makes it ideal for us to use in cases like these.

See also

Applying multiple directives to the same element using the Directive Composition API

In this recipe, you’ll use the Directive Composition API to create multiple components and apply directives to them directly for reusability instead of having to apply the directives to each component or create additional elements inside the template of the component to apply the directives.

Getting ready

The app that we are going to work with resides in start/apps/chapter02/ng-directive-comp-api inside the cloned repository:

  1. Open the code repository in your code editor.
  2. Open the terminal, navigate to the code repository directory, and run the following command to serve the project:
    npm run serve ng-directive-comp-api
    

    This should open the app in a new browser tab, and you should see the following:

    Figure 2.13: ng-directive-comp-api app running on http://localhost:4200

How to do it…

  1. First, we’ll create a couple of components for our application. We’ll create one directive for the filled button, one for the outline button, and one for a button with a tooltip. Run the following command from the start folder within the workspace:
    nx g directive button-filled --directory apps/chapter02/ng-directive-comp-api/src/app/directives --standalone=false
    nx g directive button-outlined --directory apps/chapter02/ng-directive-comp-api/src/app/directives --standalone=false
    nx g directive button-with-tooltip --directory apps/chapter02/ng-directive-comp-api/src/app/directives --standalone=false
    

    If asked, choose the @nx/angular:component schematics and choose the “As provided” action.

    Note that all the directives we have created are non-standalone directives. That is because the application is bootstrapped with an NgModule and the AppComponent is not a standalone component. Therefore, we these directives to be imported in the app.module.ts for this recipe to work.

  1. Let’s make the ButtonDirective a standalone directive, which means this isn’t going to be a part of any NgModule. Update the button.directive.ts as follows:
    ...
    @Directive({
      selector: '[appButton]',
      standalone: true,
    })
    export class ButtonDirective {
      ...
    }
    
  2. Let’s also remove it from the app.module.ts file as it is now a standalone directive. Update the app.module.ts file as follows:
    ...
    import { ButtonDirective } from './directives/button.directive'; // <-- remove the import
    ...
    @NgModule({
      declarations: [
        ...,
        ButtonDirective, // <-- remove this
        ...
      ],
      ...
    })
    export class AppModule {}
    

    You’ll notice that none of the buttons have the required styles anymore as follows:

    Figure 2.14: Styles from the button directive are gone

  1. Let’s update the ButtonFilledDirective to use the ButtonDirective using the Directive Composition API. Update the button-filled.directive.ts file as follows:
    import { Directive, HostBinding } from '@angular/core';
    import { ButtonDirective } from './button.directive';
    @Directive({
      selector: '[appButtonFilled]',
      hostDirectives: [
        {
          directive: ButtonDirective,
          inputs: ['color'],
        },
      ],
    })
    export class ButtonFilledDirective {
      @HostBinding('attr.fill')
      fill = 'filled';
    }
    
  2. We can use the appButtonFilled directive in the app.component.html file as follows:
    ...
    <main class="content" role="main">
      <ul class="flex flex-col">
        <li class="flex gap-4 items-center border-b justify-
          between border-slate-300 py-3">...</li>
        <li class="flex gap-4 items-center border-b justify-
          between border-slate-300 py-3">
          <h4 class="text-lg">Filled Button:</h4>
          <button appButtonFilled color="yellow">Click
            Me</button>
        </li>
        <li class="flex gap-4 items-center border-b justify-
          between border-slate-300 py-3">...</li>
        <li class="flex gap-4 items-center border-b justify-
          between border-slate-300 py-3">...</li>
      </ul>
    </main>
    

Notice that we’ve removed the fill attribute from the element.

  1. Let’s update the ButtonOutlined directive as well. We’ll modify the button-outlined.directive.ts as follows:
    import { Directive, HostBinding } from '@angular/core';
    import { ButtonDirective } from './button.directive';
    @Directive({
      selector: '[appButtonOutlined]',
      hostDirectives: [
        {
          directive: ButtonDirective,
          inputs: ['color'],
        },
      ],
    })
    export class ButtonOutlinedDirective {
      @HostBinding('attr.fill')
      fill = 'outlined';
    }
    
  2. Let’s also modify the ButtonWithTooltipDirective class. We’ll update the button-with-tooltip.directive.ts as follows:
    import { Directive } from '@angular/core';
    import { ButtonDirective } from './button.directive';
    import { TooltipDirective } from './tooltip.directive';
    @Directive({
      selector: '[appButtonWithTooltip]',
      hostDirectives: [
        {
          directive: ButtonDirective,
          inputs: ['color', 'fill'],
        },
        {
          directive: TooltipDirective,
          inputs: ['appTooltip: tooltip'],
        },
      ],
    })
    export class ButtonWithTooltipDirective {}
    

    You will notice that the app starts throwing an error that TooltipDirective is not a standalone component. That’s true. We need to do the same thing we did for the ButtonDirective in step 2 and step 3 for the TooltipDirective as well. Move on to the next step once you’ve done that.

  1. Now, update the app.component.html file to use both the appButtonOutlined and appButtonTooltip directives as follows:
    ...
    <main class="content" role="main">
      <ul class="flex flex-col">
        <li class="flex gap-4 items-center border-b justify-
          between border-slate-300 py-3">...</li>
        <li class="flex gap-4 items-center border-b justify-
          between border-slate-300 py-3">...</li>
        <li class="flex gap-4 items-center border-b justify-
          between border-slate-300 py-3">
          <h4 class="text-lg">Outlined Button:</h4>
          <button appButtonOutlined>Click Me</button>
        </li>
        <li class="flex gap-4 items-center border-b justify-
          between border-slate-300 py-3">
          <h4 class="text-lg">Button with Tooltip:</h4>
          <div class="flex flex-col gap-4">
            <button appButtonWithTooltip tooltip="code with
              ahsan" fill="outlined" color="blue">
              Click Me
            </button>
            <button appButtonWithTooltip tooltip="code with
              ahsan" fill="filled" color="blue">
              Click Me
            </button>
          </div>
        </li>
      </ul>
    </main>
    

    If you’ve followed all the steps correctly, you should be able to see the final result as follows:

    Figure 2.15: Final result containing buttons with different directives applied

How it works…

The Directive Composition API was introduced in Angular v15 and has been one of the most requested features from the Angular community. In this recipe, we tried to create some components that bind the directives to the component directly in the component’s TypeScript classes rather than in the template. This eliminates the need to create a wrapper element within the components to then apply the directives or to map the inputs of the components to the inputs of the directives. This also allows multiple directives to be bound to the same component – even if they may have inputs with the same names, we can alias them differently.

The flow of the directives in our application works in the following way:

  • The AppComponent uses the ButtonFilledDirective, ButtonOutlinedDirective, and ButtonWithTooltipDirective directives. For this, these directive need to be non-standalone since the application is bootstrapped with an NgModule
  • ButtonFilledDirective, ButtonOutlinedDirective, and ButtonWithTooltipDirective directives use the directive composition API to use the ButtonDirective and the TooltipDirective. These need to be standalone directives to be used as ‘hostDirectives'

The key to using the Directive Composition API is to construct your base-directives with the standalone: true flag. This means your directives aren’t part of any NgModule and can be imported directly into the imports array of any component they’re being used in. This is why we make both the ButtonDirective and the TooltipDirective standalone in steps 2, 3, and 7. Then, we use those directives in ButtonFilledDirective, ButtonOutlinedDirective, and ButtonWithTooltipDirective to be able to reuse the logic without having to create any wrapper component or additional HTML. We do it using the hostDirectives property in the directive metadata. Notice that we pass an array of objects to this property and each object can contain the directive property, which takes the class of the directive to be applied. And we can also provide inputs and outputs for the host bindings. As you saw for the ButtonWithTooltipDirective, we also aliased the appTooltip input of the TooltipDirective with the tooltip input of the ButtonWithTooltipDirective. One thing to notice is that if you don’t want to map any inputs or outputs and just want to bind a directive in the hostDirectives, you can just provide an array of the classes of the directives to be applied as follows:

hostDirectives: [
  ButtonDirective,
  TooltipDirective
],

See also

Learn more on Discord

To join the Discord community for this book – where you can share feedback, ask questions to the author, and learn about new releases – follow the QR code below:

https://packt.link/AngularCookbook2e

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Explore updated and new recipes to fill gaps in your knowledge while using Angular in production
  • Discover industry best practices and tooling to enhance your development experience with Angular’s renaissance
  • Gain an understanding of advanced Angular topics to become a proficient enterprise web developer

Description

Angular has long been the framework of choice for web development projects of various scales, offering much-needed stability and a rich tooling ecosystem for building production-ready web and mobile apps. This recipe-based guide ensures high performance apps with the latest version of Angular, helping you to build up your Angular expertise with a wide range of recipes across key tasks in web development. In this second edition, the recipes have been updated, added, and improved based on developer feedback, new challenges, and Angular 17. The first few chapters will show you how to utilize core Angular concepts such as components, directives, and services to get you ready for building frontend web apps. You’ll then develop web components with Angular and go on to learn about 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 book, you’ll be able to create full-fledged, professional-looking Angular apps and have the skills you need for frontend development.

Who is this book for?

This book is for intermediate-level Angular developers looking for actionable solutions to common problems in Angular enterprise development. Mobile developers using Angular will also find the recipes in 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
  • Get to grips with creating 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 Argentina

Standard delivery 10 - 13 business days

$12.95

Premium delivery 3 - 6 business days

$40.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Dec 29, 2023
Length: 536 pages
Edition : 2nd
Language : English
ISBN-13 : 9781803233444
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
Estimated delivery fee Deliver to Argentina

Standard delivery 10 - 13 business days

$12.95

Premium delivery 3 - 6 business days

$40.95
(Includes tracking information)

Product Details

Publication date : Dec 29, 2023
Length: 536 pages
Edition : 2nd
Language : English
ISBN-13 : 9781803233444
Vendor :
Google
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.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
$199.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
$279.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 $ 125.97
Angular Cookbook
$41.99
Learning Angular, Fourth Edition
$41.99
Angular Projects
$41.99
Total $ 125.97 Stars icon

Table of Contents

15 Chapters
Winning Component Communication Chevron down icon Chevron up icon
Working with Angular Directives and Built-In Control Flow Chevron down icon Chevron up icon
The Magic of Dependency Injection in Angular Chevron down icon Chevron up icon
Understanding Angular Animations Chevron down icon Chevron up icon
Angular and RxJS – Awesomeness Combined Chevron down icon Chevron up icon
Reactive State Management with NgRx Chevron down icon Chevron up icon
Understanding Angular Navigation and Routing Chevron down icon Chevron up icon
Mastering Angular Forms Chevron down icon Chevron up icon
Angular and the Angular CDK Chevron down icon Chevron up icon
Writing Unit Tests in Angular with Jest Chevron down icon Chevron up icon
E2E Tests in Angular with Cypress Chevron down icon Chevron up icon
Performance Optimization in Angular Chevron down icon Chevron up icon
Building PWAs with Angular Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
(13 Ratings)
5 star 69.2%
4 star 0%
3 star 7.7%
2 star 7.7%
1 star 15.4%
Filter icon Filter
Top Reviews

Filter reviews by




N/A Apr 04, 2024
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Feefo Verified review Feefo
Francisco Rodrigues Nov 11, 2024
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I'm still reading the book, but so far I'm very satisfied with the content. Well organized and objective.
Feefo Verified review Feefo
Stefan Djokic Feb 26, 2024
Full star icon Full star icon Full star icon Full star icon Full star icon 5
As a backend developer, I read this book because I was about to land on a project that uses Angular as a front-end technology. The book is quite clearly conceived, and everything is properly explained through examples. It helped me, with all the recommendations!
Amazon Verified review Amazon
Chetan Nada Jul 21, 2024
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I recently read "Angular Cookbook, 2nd Edition," by Muhammad Ahsan Ayaz and found it to be an excellent resource for mastering Angular development. The book offers over 80 actionable recipes that have deepened my understanding of Angular through practical, real-world applications.This guide helps you understand how components, services, and directives work in Angular. It's a must-have for anyone looking to improve their knowledge of this powerful framework.You'll find advanced techniques for content delivery, control flow, rich animations, parallel programming, Angular CDK, and performance optimization.Here's a brief chapter summary:Chapter 1: Communication between parent and child components.Chapter 2: Working with structural directives and the Directive Composition API.Chapter 3: Dependency injection and internal mechanisms.Chapter 4: Multi-state and keyframe animations.Chapter 5: RxJS for sequential and parallel HTTP calls.Chapter 6: Core concepts of the NgRX library.Chapter 7: Navigation and routing.Chapter 8: Template-driven and reactive forms, including testing forms.Chapter 9: Using Angular CDK for optimized content.Chapter 10: Unit testing with Jest.Chapter 11: E2E tests with Cypress, including form validation and HTTP call mocking.Chapter 12: Techniques for optimizing app performance.Chapter 13: Creating PWAs with Angular.The practical examples are well-categorized, carefully explained, and highly useful. This book is a must-have for developers. I highly recommend it to anyone eager to broaden their expertise in Angular.
Amazon Verified review Amazon
shubham kamble Jul 20, 2024
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This book is perfect for any individual or team that is looking to learn how to write scalable, enterprise-grade Angular applications. This book provides 80 actionable recipes along with code samples, design patterns, and effective narratives around challenging concepts faced by any team leveraging Angular. This book will help you become a better Angular developer.Whether you’re just getting started with Angular, or are looking for a solid reference to back up industry experience, this book will be greatly helpful.
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 customercare@packt.com 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 customercare@packt.com 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 customercare@packt.com 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 customercare@packt.com 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 customercare@packt.com 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 customercare@packt.com 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