Chapter 4. Enhancing Our Components with Pipes and Directives

In the previous chapters, we built several components that rendered data on screen with the help of input and output properties. We will leverage the knowledge in this chapter to take our components to the next level with the use of directives and pipes. In a nutshell, while pipes give us the opportunity to digest and transform the information we bind in our templates, directives allow us to conduct more ambitious functionalities where we can access the host element properties and also bind our very own custom event listeners and data bindings.

In this chapter, we will:

  • Have a comprehensive overview of the built-in directives of Angular 2
  • Discover how we can refine our data output with pipes
  • See how we can design and build our own custom pipes and directives
  • Leverage built-in objects for manipulating our templates
  • Put all the preceding topics and many more into practice by following up on our pomodoro project to build a fully interactive to-do items table

Directives in Angular 2

Angular 2 defines directives as components without views. In fact, a component is a directive with an associated template view. This distinction is used because directives are a prominent part of the Angular 2 core and each (plain directives and component directives) needs the other to exist. Directives can basically affect the way HTML elements or custom elements behave and display their content.

Core directives

Let's take a closer look at the framework's core directives, and then you will learn how to build your own directives later on in this chapter.

NgIf

As the official documentation states, the NgIf directive removes or recreates a portion of the DOM tree based on an expression. If the expression assigned to the NgIf directive evaluates to false, then the element is removed from the DOM. Otherwise, a clone of the element is reinserted into the DOM. We could enhance our countdown timer by leveraging this directive, like this:

<pomodoro-timer [seconds]="timeout"></pomodoro-timer>
<p *ngIf="timeout === 0">Time up!</p>

When our pomodoro timer reaches 0, the paragraph that displays the Time up! text will be rendered on the screen. You have probably noticed that asterisk that prepends the directive. This is because Angular embeds the HTML control marked with the NgIf directive (and all its HTML subtrees, if any) in a <template> tag, which will be used later on to render the content on the screen. Covering how Angular treats templates is definitely out of the scope of this book, but let's just point out that this is syntactic sugar provided by Angular to act as a shortcut to that other, more verbose syntax based on template tags.

Perhaps you are wondering what difference does it make to render some chunk of HTML on screen with *ngIf="conditional" rather than with [hidden]="conditional". The former will clone and inject pieces of templated HTML snippets in the markup, removing it from the DOM when the condition evaluates to false, while the latter does not inject or remove any markup from the DOM. It simply sets the visibility of the already existing chunk of HTML annotated with that DOM attribute.

NgFor

The NgFor directive allows us to iterate through a collection (or any other iterable object) and bind each of its items to a template of our choice, where we can define convenient placeholders to interpolate the item data. Each instantiated template is scoped to the outer context, where the loop directive is placed, so we can access other bindings. Let's imagine we have a component named Staff: it features a field named employees, which represents an array of Employee objects. We can enlist those employees and job titles in this way:

<ul>
  <li *ngFor="let employee of employees; let i = index; let last = last">
    Employee #{{i}}: - {{employee.name}}, {{employee.position}}
    <span *ngIf="last"><br />End of list</span>
  </li>
</ul>

As we can see in the example provided, we turn each item fetched from the iterable object on each loop into a local reference so that we can easily bind this item in our template. Here, we also use the syntax sugar that we used in the previous section, and Angular gives us the opportunity to assign index to a scoped variable that will be set to the current loop iteration in the template context. We can also assign last to a scoped variable that will inform whether the item is the last one in the iteration.

This directive observes changes in the underlying iterable object and will add, remove, or sort the rendered templates as items are added, removed, or reordered in the collection.

NgStyle

As you probably have guessed already, this directive allows us to bind CSS styles by evaluating a custom object or expression. We can bind an object whose keys and values map CSS properties, or just define specific properties and bind data to them:

<p [ngStyle]="{ 'color': myColor, 'font-weight': myFontWeight }">I am red and bold</p>

If our component defines the myColor and myFontWeight properties with the red and bold values, respectively, the color and weight of the text will change accordingly. The directive will always reflect the changes made within the component, and we can also pass an object instead of binding data on a per property basis:

<p [ngStyle]="myCssConfig">I am red and bold</p>

NgClass

Similar to NgStyle, NgClass allows us to define and toggle class names programmatically in a DOM element using a convenient declarative syntax. This syntax has its own intricacies, however. Let's see each one of the three case scenarios available for this example:

<p [ng-class]="{{myClassNames}}">Hello Angular!</p>

For instance, we can use a string type so that if myClassNames contains a string with one or several classes delimited by a space, all of them will be bound to the paragraph.

We can use an array as well so that each element will be added.

Last but not least, we can use an object in which each key corresponds to a CSS class name referred to by a Boolean value. Each key name marked as true will become an active class. Otherwise, it will be removed. This is usually the preferred way of handling class names.

NgSwitch, NgSwitchWhen, and NgSwitchDefault

The NgSwitch directive is used to switch templates within a specific set depending on the condition required for displaying each one. The implementation follows several steps, therefore three different directives are explained in this section.

NgSwitch will evaluate a given expression and then toggle and display those child elements marked with an ngSwitchWhen attribute directive, whose value matches the value thrown by the expression defined in the parent ngSwitch element. A special mention is required about the children element marked with the ngSwitchDefault directive attribute. This attribute qualifies the template that will be displayed when no other value defined by its ngSwitchWhen siblings matches the parent conditional expression.

We'll see all of this in an example:

<div [ngSwitch]="weatherForecastDay">
    <template ngSwitchWhen="today">{{weatherToday}}</template>
    <template ngSwitchWhen="tomorrow">
      {{weatherTomorrow}}</template>
    <template ngSwitchDefault>
        Pick a day to see the weather forecast
    </template>
</div>

The parent [ngSwitch] parameter evaluates the weatherForecastDay context variable, and each nested ngSwitchWhen directive will be tested against it. We can use expressions instead, but we want to wrap ngSwitchWhen in brackets so that Angular can properly evaluate its content as context variables instead of taking it as a text string.

Note

At the time of closing the writing of this book, the Angular core team is discussing the convenience of renaming ngSwitchWhen to ngSwitchCase in order to keep consistent with JavaScript and TypeScript switch/case keywords, and also with other i18n directives such as NgPlural and NgPluralCase. It is quite likely that this breaking change will make it to Angular 2 final so please refer to the online documentation to double check the final syntax for NgSwitch template cases.

Coverage for the NgPlural and NgPluralCase sits outside of the scope of this book, but basically provide a convenient way to render or remove templates DOM blocks that match a switch expression, either strictly numeric or just a string, in a similar fashion to how the NgSwitch and NgSwitchWhen directives do.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset