left-icon

Angular Succinctly®
by Joseph D. Booth

Previous
Chapter

of
A
A
A

CHAPTER 10

Templates

Templates


The templates you create as part of your component are the powerful UI pieces that let your component present data to your application user. In this chapter, we explore how to use templates to render any data your application needs to present. The template compiler is found in the @angular/compiler directory.

Template declaration

The template can be included in the metadata of the component (a good solution if the template is small) or stored in a separate file and referenced via the templateUrl property. The templateUrl property looks in the root level (same level as index.html). You can use the moduleId metadata property, set to the value module.id. The following code sample tells the component to look in the app/Views folder for the HTML.

Code Listing 56

@Component({

  selector: 'main-app',

  moduleId: module.id,

  templateUrl:  '../Views/League.html',

It is your preference as to where you would like to store your template. If you choose to store it in the metadata, you can use backtick characters (`) as delimiters to create a multiline template.

Now, let’s look at the content we can place in the template.

HTML

The templates are HTML code, with some enhancements to let them work with Angular components. Most anything that goes in HTML can be used in a template, the notable exception being the <script> tag, which will be ignored. Remember, the HTML code is meant to be embedded within a CSS selector, so tags like <html>, <header>, and <body> won’t be of much use.

Angular includes the concept of data binding, which is basically extending the HTML syntax to bring component properties and expressions into the generated template.

Interpolation

Interpolation is the simplest example of data binding. If you include a property name from your component within {{ }}, the property value will be inserted into the generated HTML. If the component changes the value of the property, the HTML snippet from that component’s template will be updated on the screen.

Expressions

You are not limited to putting property names between {{ }}; you can also use expressions. Angular will evaluate the expression (which must return a value) and convert the result to a string, which is displayed. Note that any expressions that update variables (like the increment and decrement operators) or create variables (like assignments) are not supported.

Note also that the expressions can reference component properties, but cannot reference global variables or objects. You could, however, declare the object value you want to use in your component, as shown in the following code.

Code Listing 57

  get BrowserUserAgent() : string  

  {

    return navigator.userAgent

  }

Be sure to keep your template expressions simple and free of side effects. In general, reading a property should never cause some other property or value to change.

Pipe operator

The pipe operator ( | ) allows you to apply a modifier that can control how a property appears on the screen. The basic syntax is:

Code Listing 58

{{ property | pipe_name }}

There are a number of built-in pipes included with Angular. These include:

  • uppercase: Converts property value to uppercase.
  • lowercase: Converts property value to lowercase.
  • percent: Expresses the decimal value as a percentage with the % sign.
  • currency: Converts to a specified currency.
  • date: Displays the property as a date string.

Some pipes (such as currency and date) can optionally take a parameter to further customize the data’s appearance. The parameter is separated from the pipe name by a colon ( : ). If multiple parameters are used, they are all separated by colons.

For example, if a date property is simply coded as {{ SeasonStart }}, it will appear as:

Thu Aug 11 2016 18:50:35 GMT-0400 (Eastern Daylight Time)

If we want something a little bit less wordy, we could use the date pipe with an additional format parameter.

Code Listing 59

<h4>New season starts on {{ SeasonStart | date:"fullDate" }}</h4>

This will display the date in a more readable format:

Thursday, August 11, 2016

Other date formats include:

  • medium (Aug 25, 2016, 12:59:08 PM)
  • short (8/25/2016, 12:59 PM)
  • fullDate (Thursday, August 25, 2016)
  • longDate (August 25, 2016)
  • mediumDate (Aug 25, 2016)
  • shortDate (8/25/2016)
  • mediumTime (12:59:08 PM)
  • shortTime (12:59 PM)

You can also chain pipes together. The following example will show the season start date in medium format and uppercase.

Code Listing 60

<h4>Starts on {{ SeasonStart | date:"medium" | uppercase }}</h4>

Custom pipes

You can create your own pipes for data transformation as well. For example, many web applications show dates and times in a friendlier fashion, such as “a few minutes ago…”, “tomorrow,” or “last week.” We can create a pipe that works on a date property and returns a string value to display on the site.

Creating the pipe class

You will need to create a component class, decorate it with the @Pipe keyword, and then implement the PipeTransform method from the interface.

Code Listing 61

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'FriendlyDate'})

export class FriendlyDate implements PipeTransform {}

The class code must implement the transform() method. This method takes a value parameter (of the input data type) and returns a string. You can have additional parameters if your pipe supports parameters.

Code Listing 62

transform(value: Date): string {

    let CurrentDay: Date = new Date();

    let diff: number =  Math.floor(( Date.parse(value.toString()) –

                        Date.parse(CurrentDay.toString()) ) / 86400000);

    // Check for today, tomorrow, and yesterday

    if (diff==0)      {  return "today" };

    if (diff==1)      {  return "tomorrow" };

    if (diff==-1)     {  return "yesterday "};

    // Determine day of week

    let weekdays = new Array(7);

    weekdays[0] = "Sunday";

    weekdays[1] = "Monday";

    weekdays[2] = "Tuesday";

    weekdays[3] = "Wednesday";

    weekdays[4] = "Thursday";

    weekdays[5] = "Friday";

    weekdays[6] = "Saturday";

   

    let CurWeekDay:number = CurrentDay.getDay();

    let valueDay:number = value.getDay();

    if (valueDay > CurWeekDay && diff < 7) {

      return weekdays[valueDay];

    }

    return value.toDateString();

  }

Our class code takes a date parameter and compares it to the current day. It returns yesterday, today, or tomorrow if appropriate. It then checks to see if the date is less than seven days out, and past the current weekday. If this happens, it simply displays the day name. Finally, if it cannot come up with a simple expression, it defaults to showing the date as a formatted string.

Using the custom pipe

To use the custom pipe, you will need to include it in your module declarations, as shown in the following code.

Code Listing 63: app.module.ts Excerpt

import { FriendlyDate } from './app.friendlydate';

@NgModule({

  declarations: [ AppComponent,AppStandings,AppScoring,AppAdmin,

                       FriendlyDate ],

Once it is declared, you can use it just as you would any other pipe.

Code Listing 64

    <p>Season starts: {{ SeasonStart | FriendlyDate }}  </p>

Note: This example pipe is shown only to illustrate the basics of creating custom pipes. If you want to use custom pipes, be sure to download the complete version from GitHub.

Template statements

You can bind to various events using the template statement feature of Angular. A template statement is an expression that does something, which can be an assignment or a call to a method within your component. Template statements are how data gets updated in an Angular application. A simple assignment statement might be:

Code Listing 65

ClubTitle = 'JB Soccer'

We could add a button in our template, and when the button is clicked (or another event occurs), we could execute the statement.

Code Listing 66

<button (click)="ClubTitle='JB Soccer'"> Take over club</button>

This tells Angular that when the click event of the button occurs, assign the new owner (JB Soccer) to the component property ClubTitle. If club title was in the template, it would be updated on the screen.

You can also call methods in the component to toggle between leagues on the screen, as the following example shows.

Code Listing 67

<button (click)="onToggle()"> Toggle </button>

Be sure to keep your template statements simple, such as assignments or method calls. Complicated business logic belongs in the component methods, not in the template statement.

Displaying data in templates

We’ve looked at a few simple expressions and statements to get data from our component on to the application webpage. Let’s expand our class a bit to show how we can display arrays, objects, etc., and not just the basic string and numeric data types.

Arrays

An array is a collection of TypeScript objects that can be simple base types or objects. Each element in the collection is assigned an index value, starting at zero. You can create an array using the following syntax options.

Code Listing 68

VarName: datatype [] = [ list of initial values]

For example, to declare all the leagues at a soccer club, we might use the following.

Code Listing 69

public Leagues: string[] = ['Co-ed competitive',

                            'Co-ed recreational',

                            'Over 30 mens']

This syntax would create an array of strings called Leagues and provide three initial values.

You can also create an array using the following syntax.

Code Listing 70

VarName: Array<datatype> = [ list of initial values]

The data type does not only have to be a base type, but could also be an object or interface implementation method. For example, if we have a Team class, we could use the following syntax to create an array of Teams.

Code Listing 71

public Teams: Team [] = [ new Team(1,’Nomads’),

                          new Team(2,’Old guys’) ];

Once the array is defined, all of the expected TypeScript and JavaScript methods, such as length, push, slice, etc., can be used on the array.

Interfaces

TypeScript allows you to create interfaces, which are definitions of what a class that implements the interface should look like. The interface consists of properties and methods, but no actual code. The interface serves as the blueprint for classes that implement that interface.

By convention, interface names begin with the letter i, although it’s not a requirement. The following code example shows a sample interface for a soccer team.

Code Listing 72: interfaces/team.ts

/**

 * Team interface

 */

export interface iTeam{

    id: number,

    name: string,

    type?: string     // Co-ed, Over-30, Open 

}

This interface requires an id number and a string name. It also supports an optional type property, which is a string. You can also specify methods in the interface, which a class would then be expected to provide the code for.

Note: The question mark after a property name means that the property is optional.

Classes

A class variable can also be used by itself or as an array data type. For example, we might create a Team class that implements the iTeam interface, as shown in the following code.

Code Listing 73: classes/teams.ts

import { iTeam } from '../interfaces/Teams';

class Team implements iTeam {

    public id: number;

    public name: string;

    constructor( id: number, name: string) {

        this.id = id;

        this.name = name;

    }

}

In this example, the Team class implements the iTeam interface and provides a constructor that takes the id and team name and assigns them to the public variables. We can then initialize our array as shown in the following code listing.

Code Listing 74

public Teams: Team[] = [ new Team(1,"Nomads"), new Team(2,"Old guys")];

Once you’ve created your variables and arrays, the template syntax provides methods and directives for you to manipulate them.

Conditions

You can use the *ngIf syntax in your template to conditionally build part of the template-based conditions in your component. For example, if we were to declare a Boolean value called IsAdmin in our component, the following construct could hide or show the final menu option, based on the IsAdmin value.

Code Listing 75

      <ul *ngIf="IsAdmin" class="nav navbar-nav navbar-right">

        <li>

          <a routerLink="/Admin" routerLinkActive="active" >Admin</a>

        </li>

      </ul>

You can test expressions or simple variables, so Teams.length>0 will work just as well as a Boolean variable. However, complex business conditions should be kept in the component to keep the display code as simple as possible.

Switch statement

The switch statement in Angular can be used when you have a single property or expression to be compared against multiple different values. There are two basic parts to the statement: the first provides the property or expression you wish to evaluate, and the second part is the list of values to compare the expression to.

Code Listing 76

[ngSwitch]="expression"

*ngSwitchCase="value"

*ngSwitchCase="value"

*ngSwitchDefault

You can use it to include some output in your HTML, as shown in the following example.

Code Listing 77

        <div class="container" [ngSwitch]="CurrentRole">

            <div *ngSwitchCase=10>Head Referee</div>           

            <div *ngSwitchCase=20>Referee</div>

            <div *ngSwitchCase=30>Scorekeeper</div>           

            <div *ngSwitchCase=40>Admin</div>

            <div *ngSwitchDefault>End User</div>

        </div>

This code sample assumes the component has set the CurrentRole property to a numeric value. It then tests the property value and displays a different text, depending upon the role. The final piece, the *ngSwitchDefault, provides the value to display if none of the prior conditions are met.

Looping

The *ngFor syntax is used to loop through arrays or other types of collections. It allows you to iterate each item in the collection, one at a time, and display it on the template page. The basic syntax is:

Code Listing 78

*ngFor = "let oneItem of collection"

      {{ oneItem }}

OneItem will contain whatever data type or object type was placed in the collection. For example, if we wanted to list items on the template, we could use the following code sample.

Code Listing 79

<ul>

   <li *ngFor="let oneTeam of Teams">

        {{ oneTeam }}

   </li>   

</ul>

We can also extract elements from the object. For example, if our Teams object had both a team id property and a TeamName property, we could use the following code example to build a select list, allowing the user to pick a team.

Code Listing 80

    <select (change)="onTeamChange($event.target.value)">

        <option *ngFor="let oneTeam of Teams" value={{oneTeam.id}}>

            {{ oneTeam.TeamName }}

        </option>

    </select>

The (change) syntax tells Angular to call a component method (onTeamChange) whenever the value in the select box is changed. The event target value will contain the value (team ID) of the selected element.

Summary

The Angular template system allows you to bind data from your component to display in the browser, as well as directives to control what is displayed and loop over collections. We will use these features in our example applications in the next few chapters.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.