Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Angular UI Development with PrimeNG
Angular UI Development with PrimeNG

Angular UI Development with PrimeNG: Build rich UI for Angular applications using PrimeNG

eBook
₹799.99 ₹2919.99
Paperback
₹3649.99
Subscription
Free Trial
Renews at ₹800p/m

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
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
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

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

Angular UI Development with PrimeNG

Getting Started with Angular and PrimeNG

This book presupposes some basic knowledge of TypeScript and Angular 2. Anyway, we would like to give the readers an overview of the most important TypeScript and Angular key concepts used in this book. We will summarize TypeScript and Angular features and present them in understandable, simple, but deeply explained portions. At the time of writing the book, the current TypeScript and Angular Versions are 2.3.x and 4.2.x, respectively. Readers will also meet the PrimeNG UI library for the first time and gain experience with project setups in three various ways. At the end of this chapter, readers will be able to run the first Angular- and PrimeNG-based web application.

In this chapter, we will cover the following topics:

  • TypeScript fundamentals
  • Advanced types, decorators, and compiler options
  • Angular cheat sheet - overview of key concepts
  • Angular modularity and lifecycle hooks
  • Running PrimeNG with SystemJS
  • Setting up PrimeNG project with Webpack
  • Setting up PrimeNG project with Angular CLI

TypeScript fundamentals

Angular 2 and higher is built with features of ECMAScript 2015/2016 and TypeScript. The new ECMAScript standards target evergreen browsers and helps to write more powerful, clean, and concise code. You can also use these features in any other less modern browsers with Polyfills such as core-js (https://github.com/zloirock/core-js). But, why do we need to use TypeScript?

TypeScript (http://www.typescriptlang.org) is a typed language and a super set of JavaScript developed by Microsoft. One can say that TypeScript is an advanced JavaScript with optional static typing. TypeScript code is not processed by browsers, it has to be translated into JavaScript by means of a TypeScript compiler. This translation is called compilation or transpilation. The TypeScript compiler transpiles .ts files into .js files. The main advantages of TypeScript are as follows:

  • Types help you find and fix a lot of errors during development time. That means, you have less errors at runtime.
  • Many modern ECMAScript features are supported out of the box. More features are expected according to the roadmap (https://github.com/Microsoft/TypeScript/wiki/Roadmap).
  • Great tooling and IDE support with IntelliSense makes the coding a pleasure.
  • It is easier to maintain and refactor a TypeScript application than one written in untyped JavaScript.
  • Developers feel comfortable with TypeScript due to object-oriented programming patterns, such as interfaces, classes, enums, generics, and so on.
  • Last but not least, Angular 2+ and PrimeNG are written in TypeScript.

It is also important to keep the following points in mind:

  • The Typescript Language Specification says, every JavaScript program is also a TypeScript program. Hence, a migration from JavaScript to TypeScript code is easily done.
  • TypeScript compiler emits output even when any errors are reported. In the next section, Advanced types, decorators, and compiler options, we will see how we can forbid emitting JavaScript on errors.

What is the best way to learn the TypeScript language? There is an official handbook on the TypeScript's homepage, which is aligned with the last released version. Hands-on learning is possible with the TypeScript playground (http://www.typescriptlang.org/play), which compiles on-the-fly TypeScript code entered in a browser and shows it side by side with the generated JavaScript code:

Alternatively, you can install the TypeScript globally by typing the following command in the command line:

npm install -g typescript

Global installation means, the TypeScript compiler tsc can be reached and used in any of your projects. Installed Node.js and npm are presupposed. Node.js is the JavaScript runtime environment (https://nodejs.org). npm is the package manager. It is shipped with Node.js, but can be installed separately as well. After that, you can transpile one or more .ts files into .js files by typing the following command:

tsc some.ts another.ts

This will result in two files, some.js and another.js.

Basic types

TypeScript exposes the basic types, as well as a couple of extra types. Let's explore the type system with these examples.

  • Boolean: The type is a primitive JavaScript boolean:
let success: boolean = true;
  • Number: The type is a primitive JavaScript number:
let count: number = 20;
  • String: The type is a primitive JavaScript string:
let message: string = "Hello world";
  • Array: The type is an array of value. There are two equivalent notations:
let ages: number[] = [31, 20, 65];
let ages: Array<number> = [31, 20, 65];
  • Tuple: The type represents a heterogeneous array of values. Tuple enables storing multiple fields of different types:
let x: [string, number];
x = ["age", 40]; // ok
x = [40, "age"] ; // error
  • Any: The type is anything. It is useful when you need to describe the type of variables that you do not know at the time of writing your application. You can assign a value of arbitrary type to a variable of type any. A value of type any in turn can be assigned to a variable of arbitrary type:
let some: any = "some";
some = 10000;
some = false;

let success: boolean = some;
let count: number = some;
let message: string = some;
  • Void: The type represents the absence of having an any type. This type is normally used as the return type of functions:
function doSomething(): void {
// do something
}
  • Nullable: These types denote two specific types, null and undefined that are valid values of every type. That means, they can be assigned to any other type. It is not always desired. TypeScript offers a possibility to change this default behavior by setting the compiler options strictNullChecks to true. Now, you have to include the Nullable types explicitly using a union type (explained later on), otherwise, you will get an error:
let x: string = "foo";
x = null; // error
let y: string | null = "foo";
y = null; // ok

Sometimes, you would like to tell compiler that you know the type better than it does and it should trust you. For instance, imagine a situation where you receive data over HTTP and know exactly the structure of the received data. The compiler doesn't know such structure of course. In this case, you want to turn off the type checking when assigning the data to a variable. It is possible with so called type assertions. A type assertion is like a type cast in other languages, but without the checking of data. You can do that either with angle bracket or the as syntax.

let element = <HTMLCanvasElement> document.getElementById('canvas');
let element = document.getElementById('canvas') as HTMLCanvasElement;

Interfaces, classes, and enums

An interface is a way to take a particular structure/shape and give it a name so that we can reference it later as a type. It defines a contract within our code. Interfaces begin with the keyword interface. Let's take an example:

interface Person {
name: string
children?: number
isMarried(): boolean
(): void
}

The specified interface Person has the following:

  • The name property of type string.
  • The optional property children of type number. Optional properties are denoted by a question mark and can be omitted.
  • The isMarried method that returns a boolean value.
  • Anonymous (unnamed) method that returns nothing.

Typescript allows you to use the syntax [index: type] to specify a string or number type based collection of key/value pairs. Interfaces perfectly fit such data structures. For example, consider the following syntax:

interface Dictionary {
[index: number]: string
}
An interface is only used by TypeScript compiler at compile time, and is then removed. Interfaces don't end up in the final JavaScript output. General, no types appear in the output. You can see that in the TypeScript playground mentioned earlier.

Beside interfaces, there are classes that describe objects. A class acts as a template for instantiating specific objects. The syntax for TypeScript's classes is almost identical to that of native classes in ECMAScript 2015 with some handy additions. In TypeScript, you can use public, private, protected, and readonly access modifiers:

class Dog {
private name: string; // can only be accessed within this class
readonly owner: string = "Max"; // can not be modified
constructor(name: string) {this.name = name;}
protected sayBark() { }
}

let dog = new Dog("Sam");
dog.sayBark(); // compiler error because method 'sayBark' is protected and
// only accessible within class 'Dog' and its subclasses.

Members with omitted modifiers are public by default. If a property or method is declared with the static keyword, there is no need to create an instance to access them.

A class can be abstract, that means, it may not be instantiated directly. Abstract classes begin with the keyword abstract. A class can implement an interface as well as extend another class. We can achieve that using the implements and extends keywords, respectively. If a class implements some interface, it must adopt all properties from this interface; otherwise, you will get an error about missing properties:

interface Animal {
name: string;
}

class Dog implements Animal {
name: string;
// do specific things
}

class Sheepdog extends Dog {
// do specific things
}
Derived classes that contain constructor functions must call super(). The super() call executes the constructor function on the base class.

It is possible to declare a constructor parameter with a modifier. As result, a member will be created and initialized in one place:

class Dog {
constructor(private name: string) { }

// you can now access the property name by this.name
}
This shortened syntax is often used in Angular when we inject services into components. Angular's services are normally declared in the component's constructor with the private modifier.

The last basic type to be mentioned here is enum. Enums allow us to define a set of named constants. Enum members have numeric values associated with them (started with 0):

enum Color {
Red,
Green,
Blue
}

var color = Color.Red; // color has value 0

Functions

Parameters and return values in the function signature can be typed too. Types protects you against JavaScript errors during function execution because the compiler warns you punctually at build time when the wrong types are used:

function add(x: number, y: number): number {
return x + y;
}

Function type is a way to declare the type of a function. To explicitly declare a function type, you should use the keywords var or let, a variable name, a colon, a parameter list, a fat arrow =>, and the function's return type:

var fetchName: (division: Division, customer: Customer) => string;

Now, you must provide an implementation of this declaration:

fetchName = function (division: Division, customer: Customer): string {
// do something
}

This technique is especially useful for callbacks. Imagine a filter function which filters arrays by some criterion. An exact criterion can be encapsulated in the passed in callback function that acts as predicate:

function filter(arr: number[], callback: (item: number) => boolean): number[] {
let result: number[] = [];
for (let i = 0; i < arr.length; i++) {
if (callback(arr[i])) {
result.push(arr[i]);
}
}
return result;
}

A possible function call with a specific callback could appear as follows:

let result = filter([1, 2, 3, 4], (item: number) => item > 3);

In TypeScript, every function parameter is assumed to be required. There are two ways to mark a parameter as optional (optional parameters can be omitted when calling the function).

  • Use a question mark after the parameter name:
function doSomething(param1: string, param2?: string) {
// ...
}
  • Use the parameter's default value (ECMAScript 2015 feature), which gets applied when no value is provided:
function doSomething(param1: string, param2 = "some value") {
// ...
}

Now, you are able to call this function with just one value.

doSomething("just one value");

Generics

In TypeScript, you can define generic functions, interfaces, and classes like in other programming languages. A generic function has type parameters listed in angle brackets:

function reverseAndMerge<T>(arr1: T[], arr2: T[]): T[] {
return arr1.reverse().concat(arr2.reverse());
}

let arr1: number[] = [1, 2, 3];
let arr2: number[] = [4, 5, 6];
let arr = reverseAndMerge(arr1, arr2);

Such generic functions can be defined with generic interfaces as well. The function signature for reverseAndMerge is compatible with the following generic interface:

interface GenericArrayFn<T> {
(arr1: T[], arr2: T[]): T[];
}

let arr: GenericArrayFn<number> = reverseAndMerge;

Note that the generic type parameter list in angle brackets follows the name of the function and interface. This is also true for classes:

class GenericValue<T> {
constructor(private value: T) { }
increment: (x: T) => T;
decrement: (x: T) => T;
}

let genericValue = new GenericValue<number>(5);
genericValue.increment = function (x) {return ++x;};
genericValue.decrement = function (x) {return --x;};

Modules

ECMAScript 2015 has introduced built-in modules. The features of modules are as follows:

  • Each module is defined in its own file.
  • Functions or variables defined in a module are not visible outside unless you explicitly export them.
  • You can place the export keyword in front of any variable, function, or class declaration to export it from the module.
  • You can use the import keyword to consume the exported variable, function, or class declaration.
  • Modules are singletons. Only a single instance of a module exists, even if it was imported multiple times.

Some exporting possibilities are listed here:

// export data
export let color: string = "red";

// export function
export function sum(num1: number, num2: number) {
return num1 + num1;
}

// export class
export class Rectangle {
constructor(private length: number, private width: number) { }
}

You can declare a variable, function, or class and export it later. You can also use the as keyword to rename exports. A new name is the name used for importing:

class Rectangle {
constructor(private height: number, private width: number) { }
}

export {Rectangle as rect};

Once you have a module with exports, you can access its functionality in another module using the import keyword:

import {sum} from "./lib.js";
import {Rect, Circle} from "./lib.js";

let sum = sum(1, 2);
let rect = new Rect(10, 20);

There is a special case that allows you to import the entire module as a single object. All exported variables, functions, and classes are available on that object as properties:

import * as lib from "./lib.js";

let sum = lib.sum(1, 2);

Imports can be renamed with the as keyword and used under the new name:

import {sum as add} from "./lib.js";

let sum = add(1, 2);

Advanced types, decorators, and compiler options

TypeScript has more types and advanced constructs such as decorators and type definition files. This chapter gives an overview on advanced topics and shows how to customize the compiler configuration.

Union types and type aliases

A union type describes a value that can be one of many types. The vertical bar | is used as separator for each type the value can have. For instance, number | string is the type of a value that can be a number or string. For such values, we can only access members that are common to all types in the union. The following code works because the length property exists on both strings and arrays:

var value: string | string[] = 'some';
let length = value.length;

The next code snippet gives an error because the model property does not exist on the Bike type:

interface Bike {
gears: number;
}

interface Car {
gears: number;
model: string;
}

var transport: Bike | Car = {gears: 1};
transport.model = "Audi"; // compiler error

Type alias is used as alternative name for the existing type or combination of types. It doesn't create a new type. A type alias begins with the type keyword.

type PrimitiveArray = Array<string|number|boolean>;
type Callback = () => number;
type PrimitiveArrayOrCallback = PrimitiveArray | Callback;

Type aliases can be used for better code readability, for example, in the function parameter list.

function doSomething(n: PrimitiveArrayOrCallback): number {
...
}

Type aliases can also be generic and make tricky types, which can not be made with interfaces.

Type inference

Type inference is used when the type is not provided explicitly. For instance in the following statements:

var x = "hello";
var y = 99;

These don't have explicit type annotations. TypeScript can infer that x is a string and y is a number. As you see, the type can be omitted if the compiler is able to infer it. TypeScript improves the type inference continuously. It tries to guess a best common type when elements of several types are present in an array. The type of the following variable animal, where Sheepdog extends Dog, is Dog[]:

let animal = [new Dog(), new Sheepdog()];

The best common type of the next array is (Dog | Fish)[] because the class Fish doesn't extend to any other class:

class Fish {
kind: string;
}

let animal = [new Dog(), new Sheepdog(), new Fish()];

Type inference is also used for functions. In the next example, the compiler can figure out the types of the function's parameter (string) and the return value (boolean):

let isEmpty: (param: string) => boolean;
isEmpty = function(x) {return x === null || x.length === 0};

Decorators

Decorators were proposed in ECMAScript 2016 (https://github.com/wycats/javascript-decorators). They are similar to Java annotations--they also add metadata to class declaration, method, property, and the function's parameter, but they are more powerful. They add new behaviors to their targets. With decorators, we can run arbitrary code before, after, or around the target execution, like in aspect-oriented programming, or even replace the target with a new definition. In TypeScript, you can decorate constructors, methods, properties, and parameters. Every decorator begins with the @ character followed by the name of the decorator.

How does it work under the hood that takes its target as argument? Let's implement a classic example with a logging functionality. We would like to implement a method decorator @log. A method decorator accepts three arguments: an instance of the class on which the method is defined, a key for the property, and the property descriptor (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).

If the method decorator returns a value, it will be used as a new property descriptor for this method:

const log = (target: Object, key: string | symbol, descriptor: PropertyDescriptor) => {
// save a reference to the original method
var originalMethod = descriptor.value;
// replace the original function
descriptor.value = function(...args: any[]) {
console.log("Arguments: ", args.join(", "));
const result = originalMethod.apply(target, args);
console.log("Result: ", result);
return result;
}
return descriptor;
}

class Rectangle {
@log
area(height: number, width: number) {
return height * width;
}
}

let rect = new Rectangle();
let area = rect.area(2, 3);

This decorator logs received arguments and return values. Decorators can be composed and customized with parameters too. You can write the following, for instance:

class Rectangle {
@log("debug")
@persist("localStorage")
area(height: number, width: number) {
return height * width;
}
}

Angular offers different types of decorators that are used for dependency injection or adding metadata information at compilation time:

  • Class decorators such as @NgModule, @Component, and @Injectable
  • Property decorators such as @Input and @Output
  • Method decorators such as @HostListener
  • Parameter decorators such as @Inject

TypeScript compiler is able to emit some design-time type metadata for decorators. To access this information, we have to install a Polyfill called reflect-metadata:

npm install reflect-metadata --save

Now we can access, for example, the type of the property (key) on the target object as follows:

let typeOfKey = Reflect.getMetadata("design:type", target, key);
Refer to the official TypeScript documentation to learn more about decorators and reflect metadata API (http://www.typescriptlang.org/docs/handbook/decorators.html).
In TypeScript, Angular applications, decorators are enabled by setting the compiler options emitDecoratorMetadata and experimentalDecorators to true (compiler options are described later on).

Type definition files

JavaScript programs written in native JavaScript don't have any type information. If you add a JavaScript library such as jQuery or Lodash to your TypeScript-based application and try to use it, the TypeScript compiler can find any type information and warn you with compilation errors. Compile-time safety, type checking, and context-aware code completion get lost. That is where type definition files come into play.

Type definition files provide type information for JavaScript code that is not statically typed. Type definition files ends with .d.ts and only contain definitions which are not emitted by TypeScript. The declare keyword is used to add types to JavaScript code that exists somewhere. Let's take an example. TypeScript is shipped with the lib.d.ts library describing ECMAScript API. This type definition file is used automatically by the TypeScript compiler. The following declaration is defined in this file without implementation details:

declare function parseInt(s: string, radix?: number): number;

Now, when you use the parseInt function in your code, the TypeScript compiler ensures that your code uses the correct types and IDEs show context-sensitive hints when you're writing code. Type definition files can be installed as dependencies under the node_modules/@types directory by typing the following command:

npm install @types/<library name> --save-dev

A concrete example for jQuery library is:

npm install @types/jquery --save-dev
In Angular, all type definition files are bundled with Angular npm packages and located under node_modules/@angular. There is no need to install such files separately like we did for jQuery. TypeScript finds them automatically.

Most of the time, you have the compile target ES5 (generated JavaScript version, which is widely supported), but want to use some ES6 (ECMAScript 2015) features by adding Polyfills. In this case, you must tell the compiler that it should look for extended definitions in the lib.es6.d.ts or lib.es2015.d.ts file. This can be achieved in compiler options by setting the following:

"lib": ["es2015", "dom"]

Compiler options

Typically, the first step in a new TypeScript project is to add in a tsconfig.json file. This file defines the project and compiler settings, for instance, files and libraries to be included in the compilation, output structure, module code generation, and so on. A typical configuration in tsconfig.json for Angular 2+ projects looks like the following:

{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"moduleResolution": "node",
"noImplicitAny": true,
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"outDir": "dist",
"lib": ["es2015", "dom"]
},
"types": ["node"],
"exclude": ["node_modules", "dist"]
}

The listed compiler settings are described as follows. A full list of all options is available at the TypeScript documentation page (https://www.typescriptlang.org/docs/handbook/compiler-options.html).

Option Type Default Description
target string ES3 This specifies ECMAScript target version: ES3, ES5, ES2015, ES2016, and ES2017.
module string ES6 if target is "ES6" and CommonJS otherwise This specifies the format of module code generation: None, CommonJS, AMD, System, UMD, ES6, or ES2015.
moduleResolution string Classic if module is "AMD," System, ES6, and Node otherwise This determines how modules get resolved. Either Node for Node.js style resolution or Classic.
noImplicitAny boolean false This raises errors on expressions and declarations with an implied any type.
sourceMap boolean false This generates the corresponding .map file. This is useful if you want to debug original files.
emitDecoratorMetadata boolean false This emits design type metadata for decorated declarations in source. You have to set this value to true if you want to develop web applications with Angular.
experimentalDecorators boolean false This enables experimental support for ECMAScript decorators. You have to set this value to true if you want to develop web applications with Angular.
outDir string - This is the output directory for compiled files.
lib string[] Refer to the documentation for more information. This is the list of library files to be included in the compilation. Refer to the documentation for more information.
types string[] - This is the list of names of type definitions to include.
exclude string[] - This is the list of (sub) directories excluded from the compilation.
You can stop the compiler from emitting JavaScript on errors by setting the --noEmitOnError option to true.

Angular cheat sheet - overview of key concepts

Angular 2 introduces completely new concepts for building web applications. The new Angular platform is complex. It is not possible to explain numerous Angular features in detail. Instead, we will concentrate on the most important key concepts such as dependency injection, components, and communication between them, built-in directives, services, template syntax, forms, and routing.

Components, services, and dependency injection

Normally, you write Angular applications by composing HTML templates with the Angular-specific markup and component classes to manage those templates. A component is simply a TypeScript class annotated with @Component. The @Component decorator is used to define the associated metadata. It expects an object with the following most used properties:

  • selector: This is the name of the HTML tag representing this component
  • template: This is an inline-defined template with HTML/Angular markup for the view
  • templateUrl: This is the path to an external file where the template resides
  • styles: An inline-defined styles to be applied to this component's view
  • styleUrls: An array of paths to external files with styles to be applied to this component's view
  • providers: An array of providers available to this component and its children
  • exportAs: This is the name under which the component instance is exported in a template
  • changeDetection: This is the change detection strategy used by this component
  • encapsulation: This is the style encapsulation strategy used by this component

A component class interacts with the view through an API of properties and methods. Component classes should delegate complex tasks to services where the business logic resides. Services are just classes that Angular instantiates and then injects into components. If you register services at the root component level, they act as singletons and share data across multiple components. In the next section, Angular modularity and lifecycle hooks, we will see how to register services. The following example demonstrates how to use components and services. We will write a service class ProductService and then specify an argument of type ProductService in the constructor of ProductComponent. Angular will automatically inject that service into the component:

import {Injectable, Component} from '@angular/core';

@Injectable()
export class ProductService {
products: Product[];

getProducts(): Array<Product> {
// retrieve products from somewhere...
return products;
}
}

@Component({
selector: 'product-count',
template: `<h2 class="count">Found {{products.length}} products</h2>`,
styles: [`
h2.count {
height: 80px;
width: 400px;
}
`]
})
export default class ProductComponent {
products: Product[] = [];

constructor(productService: ProductService) {
this.products = productService.getProducts();
}
}
Notice that we applied the @Injectable() decorator to the service class. This is necessary for emitting metadata that Angular needs to inject other dependencies into this service. Using @Injectable is a good programming style even if you don't inject other services into your service.

It is good to know what an item in the providers array looks like. An item is an object with the provide property (symbol used for dependency injection) and one of the three properties useClass, useFactory, or useValue that provide implementation details:

{provide: MyService, useClass: MyMockService}
{provide: MyService, useFactory: () => {return new MyMockService()}}
{provide: MyValue, useValue: 50}

Templates and bindings

A template tells Angular how to render the component's view. Templates are HTML snippets with the specific Angular's template syntax, such as interpolation, property, attribute, and event bindings, built-in directives, and pipes to mention just a few. We will give you a quick overview of the template syntax starting with interpolation. Interpolation is used to evaluate expressions in double curly braces. The evaluated expression is then converted to a string. The expression can contain any mathematical calculations, component's properties and methods, and many more:

<p>Selected car is {{currentCar.model}}</p>

Angular evaluates template expressions after every change detection cycle. Change detection cycles are triggered by many asynchronous activities such as HTTP responses, key and mouse events, and many more. The next fundamental template syntax is related to various bindings. Property binding sets an element property to a component property value. The element property is defined in square brackets:

<img [src]="imageUrl">
<button [disabled]="formValid">Submit</button>

Here, imageUrl and formValid are a component's properties. Note that this is a one-way binding because the data flow occurs in one direction, from the component's properties into target element properties. Attribute binding allows us to set an attribute. This kind of binding is used when there is no element property to bind. The attribute binding uses square brackets too. The attribute name itself is prefixed with attr., for example, consider ARIA attributes for web accessibility:

<button [attr.aria-expanded]="expanded" [attr.aria-controls]="controls">
Click me
</button>

User interactions result in a data flow from an element to a component. In Angular, we can listen for certain key, mouse, and touch events by means of event binding. The event binding syntax consists of a target event name within parentheses on the left and a quoted template statement on the right. In particular, you can call a component's method. In the next code snippet, the onSave() method is called on a click:

<button (click)="onSave()">Save</button>

The method (generally template statement) gets a parameter--an event object named $event. For native HTML elements and events, $event is a DOM event object:

<input [value]="name" (input)="name=$event.target.value">

Two-way binding is possible as well. The [(value)] syntax combines the brackets of property binding with the parentheses of event binding. Angular's directive NgModel is best suited for the two-way binding on native or custom input elements. Consider the following sample:

<input [(ngModel)]="username">

Is equivalent to:

<input [value]="username" (input)="username=$event.target.value">

Two-way binding in a nutshell: a property gets displayed and updated at the same time when the user makes changes. A template reference variable is another example of handy template syntax. You can declare a variable with the hash symbol (#) on any DOM element and reference this variable anywhere in the template. The next example shows the username variable declared on an input element. This reference variable is consumed on a button--it is used to get an input value for the onclick handler:

<input #username>
<button (click)="submit(username.value)">Ok</button>

A template reference variable can also be set to a directive. A typical example is the NgForm directive which provides useful details about the form elements. You can, for example, disable the submit button if the form is not valid (required fields are not filled in and so on):

<form #someForm="ngForm">
<input name="name" required [(ngModel)]="name">
...
<button type="submit" [disabled]="!someForm.form.valid">Ok</button>
</form>

Last but not least, the pipe operator (|). It is used for the transformation of the expression's result. The pipe operator passes the result of an expression on the left to a pipe function on the right. For example, the pipe date formats JavaScript Date object according to the specified format (https://angular.io/docs/ts/latest/api/common/index/DatePipe-pipe.html):

Release date: {{releaseDate | date: 'longDate'}}
// Output: "August 30, 2017"

Multiple chained pipes can be applied as well.

Built-in directives

Angular has a lot of built-in directives: ngIf, ngFor, ngSwitch, ngClass, and ngStyle. The first three directives are so called structural directives, which are used to transform the DOM's structure. Structural directives start with an asterisk (*). The last two directives manipulate the CSS classes and styles dynamically. Let's explain the directives in the examples.

The ngIf directive adds and removes elements in the DOM, based on the Boolean result of an expression. In the next code snippet, <h2>ngIf</h2> is removed when the show property evaluates to false and gets recreated otherwise:

<div *ngIf="show">
<h2>ngIf</h2>
</div>

Angular 4 has introduced a new else clause with the reference name for a template defined by ng-template. The content within ng-template is shown when the ngIf condition evaluates to false:

<div *ngIf="showAngular; else showWorld">
Hello Angular
</div>
<ng-template #showWorld>
Hello World
</ng-template>

ngFor outputs a list of elements by iterating over an array. In the next code snippet, we iterate over the people array and store each item in a template variable called person. This variable can be then accessed within the template:

<ui>
<li *ngFor="let person of people">
{{person.name}}
</li>
</ui>

ngSwitch conditionally swaps the contents dependent on condition. In the next code snippet, ngSwitch is bound to the choice property. If ngSwitchCase matches the value of this property, the corresponding HTML element is displayed. If no matching exists, the element associated with ngSwitchDefault is displayed:

<div [ngSwitch]="choice">
<h2 *ngSwitchCase="'one'">One</h3>
<h2 *ngSwitchCase="'two'">Two</h3>
<h2 *ngSwitchDefault>Many</h3>
</div>

ngClass adds and removes CSS classes on an element. The directive should receive an object with class names as keys and expressions as values that evaluate to true or false. If the value is true, the associated class is added to the element. Otherwise, if false, the class is removed from the element:

<div [ngClass]="{selected: isSelected, disabled: isDisabled}">

ngStyle adds and removes inline styles on an element. The directive should receive an object with style names as keys and expressions as values that evaluate to style values. A key can have an optional .<unit> suffix (for example, top.px):

<div [ngStyle]="{'color': 'red', 'font-weight': 'bold', 'border-top': borderTop}">
In order to be able to use built-in directives in templates, you have to import CommonModule from @angular/common and add it to the root module of your application. Angular's modules are explained in the next chapter.

Communication between components

Components can communicate with each other in a loosely coupled manner. There are various ways Angular's components can share data, including the following:

  • Passing data from parent to child using @Input()
  • Passing data from child to parent using @Output()
  • Using services for data sharing
  • Calling ViewChild, ViewChildren, ContentChild, and ContentChildren
  • Interacting with the child component using a local variable

We will only describe the first three ways. A component can declare input and output properties. To pass the data from a parent to a child component, the parent binds the values to the input properties of the child. The child's input property should be decorated with @Input(). Let's create TodoChildComponent:

@Component({
selector: 'todo-child',
template: `<h2>{{todo.title}}</h2>`
})
export class TodoChildComponent {
@Input() todo: Todo;
}

Now, the parent component can use todo-child in its template and bind the parent's todo object to the child's todo property. The child's property is exposed as usual in square brackets:

<todo-child [todo]="todo"></todo-child>

If a component needs to pass the data to its parent, it emits custom events via the output property. The parent can create a listener to a particular component's event. Let's see that in action. The child component ConfirmationChildComponent exposes an EventEmitter property decorated with @Output() to emit events when the user clicks on buttons:

@Component({
selector: 'confirmation-child',
template: `
<button (click)="accept(true)">Ok</button>
<button (click)="accept(false)">Cancel</button>
`
})
export class ConfirmationChildComponent {
@Output() onAccept = new EventEmitter<boolean>();

accept(accepted: boolean) {
this.onAccept.emit(accepted);
}
}

The parent subscribes an event handler to that event property and reacts to the emitted event:

@Component({
selector: 'confirmation-parent',
template: `
Accepted: {{accepted}}
<confirmation-child (onAccept)="onAccept($event)"></confirmation-child>
`
})
export class ConfirmationParentComponent {
accepted: boolean = false;

onAccept(accepted: boolean) {
this.accepted = accepted;
}
}

A bi-directional communication is possible via services. Angular leverages RxJS library (https://github.com/Reactive-Extensions/RxJS) for asynchronous and event-based communication between several parts of an application as well as between an application and remote backend. The key concepts in the asynchronous and event-based communication are Observer and Observable. They provide a generalized mechanism for push-based notification, also known as the observer design pattern. Observable represents an object that sends notifications, and Observer represents an object that receives them.

Angular implements this design pattern everywhere. For example, Angular's Http service returns an Observable object:

constructor(private http: Http) {}

getCars(): Obvervable<Car[]> {
return this.http.get("../data/cars.json")
.map(response => response.json().data as Car[]);
}

In case of the inter-component communication, an instance of the Subject class can be used. This class inherits both Observable and Observer. That means it acts as a message bus. Let's implement TodoService that allows us to emit and receive Todo objects:

@Injectable()
export class TodoService {
private subject = new Subject();

toggle(todo: Todo) {
this.subject.next(todo);
}

subscribe(onNext, onError, onComplete) {
this.subject.subscribe(onNext, onError, onComplete);
}
}

Components can use this service in the following way:

export class TodoComponent {
constructor(private todosService: TodosService) {}

toggle(todo: Todo) {
this.todosService.toggle(todo);
}
}

export class TodosComponent {
constructor(private todosService: TodosService) {
todosService.subscribe(
function(todo: Todo) { // TodoComponent sent todo object },
function(e: Error) { // error occurs },
function() { // completed }
);
}
}

Forms

Forms are the main building blocks in every web application. Angular offers two approaches to build forms: template-driven forms and reactive forms. This section gives you a short overview of template-driven forms.

Reactive forms are suitable when you need to create dynamic forms programmatically in the component's class. Refer to the official Angular documentation to learn reactive forms (https://angular.io/docs/ts/latest/guide/reactive-forms.html).

We already mentioned two directives: NgForm and NgModel. The first directive creates a FormGroup instance and binds it to a form in order to track aggregate form value and validation status. The second one creates a FormControl instance and binds it to the corresponding form element. The FormControl instance tracks the value and the status of the form element. Each input element should have a name property that is required to register the FormControl by the FormGroup under the name you assigned to the name attribute. How to deal with this tracked data? You can export the NgForm and NgModel directives into local template variables such as #f="ngForm" and #i="ngModel", respectively. Here, f and i are local template variables that give you access to the value and status of FormGroup and FormControl, respectively. This is possible because the properties from FormGroup and FormControl are duplicated on the directives themselves. With this knowledge in hand, you can now check if the whole form or a particular form element:

  • Is valid (valid and invalid properties)
  • Has been visited (touched and untouched properties)
  • Has some changed value (dirty and pristine properties)

The next example illustrates the basic concept:

<form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate>
<label for="name">Name</label>
<input type="text" id=name" name="name" required
[(ngModel)]="name" #i="ngModel">
<div [hidden]="i.valid || i.pristine">
Name is required
</div>
<button>Submit</button>
</form>

// Output values and states
Input value: {{i.value}}
Is input valid? {{i.valid}}
Input visited? {{i.touched}}
Input value changed? {{i.dirty}}
Form input values: {{f.value | json}}
Is form valid? {{f.valid}}
Form visited? {{f.touched}}
Form input values changed? {{f.dirty}}

The NgModel directive also updates the corresponding form element with specific CSS classes that reflect the element's state. The following classes are added/removed dependent on the current state:

State Class if true Class if false
Element has been visited ng-touched ng-untouched
Element's value has changed ng-dirty ng-pristine
Element's value is valid ng-valid ng-invalid

 

This is handy for styling. For example, in case of validation errors, you can set red borders around input elements:

input.ng-dirty.ng-invalid {
border: solid 1px red;
}

Routing

Angular's router module allows you to configure navigation in a single page application without a full page reload. The router can display different views (compiled component templates) within a special tag called <router-outlet>. During navigation, one view will be replaced by another one. A simple routing configuration looks as follows:

const router: Routes = [
{path: '', redirectTo: 'home', pathMatch: 'full'},
{path: 'home', component: HomeComponent},
{path: 'books', component: BooksComponent}
];

When you navigate to the web context root, you will be redirected to /home. As a reaction to that, the view of the HomeComponent will be displayed in <router-outlet>. It is obvious that a direct navigation to /home displays the same view. A navigation to /books displays the view of BooksComponent. Such router configuration should be converted to an Angular's module by RouterModule.forRoot:

const routes: ModuleWithProviders = RouterModule.forRoot(router);

This is then imported in a root module class. In addition to the root module, an Angular application can consist of a lot of feature or lazy-loaded modules. Such separate modules can have their own router configurations which should be converted to Angular's modules with RouterModule.forChild(router). The next section, Angular modularity and lifecycle hooks, discusses modules in detail. Angular offers two strategies for implementing client-side navigation:

  • HashLocationStrategy: This strategy adds a hash sign (#) to the base URL. Everything after this sign represents a hash fragment of the browser's URL. The hash fragment identifies the route. For example, http://somehost.de:8080/#/books. Changing the route doesn't cause a server-side request. Instead, the Angular application navigates to a new route and view. This strategy works with all browsers.
  • PathLocationStrategy: This strategy is based on the History API and only works in browsers that support HTML5. This is the default location strategy.

The details are to be mentioned here. If you want to use the HashLocationStrategy, you have to import two classes, LocationStrategy and HashLocationStrategy from '@angular/common' and configure providers as follows:

providers: [{provide: LocationStrategy, useClass: HashLocationStrategy}]

Providers are described in the next section, Angular modularity and lifecycle hooks. The PathLocationStrategy class requires a configuration of the base URL for the entire application. The best practice is to import APP_BASE_HREF constant from '@angular/common' and use it as a provider in order to configure the base URL:

providers: [{provide: APP_BASE_HREF, useValue: '/'}]

How to trigger a navigation? You can achieve that in two ways, either by a link with a routerLink property, which specifies an array consisting of route (path) and optional parameters:

<a [routerLink]="['/']">Home</a>
<a [routerLink]="['/books']">Books</a>

<router-outlet></router-outlet>

Or programmatically, by invoking the navigate method on Angular's Router service:

import {Router} from '@angular/router';

...

export class HomeComponent {

constructor(private router: Router) { }

gotoBooks() {
this.router.navigate(['/books']);
}
}

You can also pass parameters to a route. Placeholders for parameters start with a colon (:):

const router: Routes = [
...
{path: 'books/:id', component: BookComponent}
];

Now, when navigating to a book with real parameters, for example, programmatically as this.router.navigate(['/books/2']), the real parameter can be accessed by ActivatedRoute:

import {ActivatedRoute} from '@angular/router';

...

export class BooksComponent {
book: string;

constructor(private route: ActivatedRoute) {
this.book = route.snapshot.params['id'];
}
}

The router outlet can be named as well:

<router-outlet name="author"></router-outlet>

The associated configuration should contain the outlet property with the name of the router outlet:

{path: 'author', component: AuthorComponent, outlet: 'author'}

Angular modularity and lifecycle hooks

Angular modularity with NgModules provides a great way to organize the code in a web application. Many third-party libraries, such as PrimeNG, Angular Material, Ionic, are distributed as NgModules. Lifecycle hooks allow us to perform custom logic at component level at a well-defined time. This section covers these major concepts in detail.

Modules and bootstrapping

Angular modules make it possible to consolidate components, directives, services, pipes, and many more into cohesive blocks of functionality. Angular's code is modularized. Every module has its own functionality. There are FormsModule, HttpModule, RouterModule, and many other modules as well. What does a module look like? A module is a class annotated with the @NgModule decorator (imported from @angular/core). @NgModule takes a configuration object that tells Angular how to compile and run the module code. The most significant properties of the the configuration object are:

  • declarations: The array with components, directives, and pipes, which are implemented in that module and belong to that module.
  • imports: The array with dependencies in form of other modules which need to be made available to that module.
  • exports: The array of components, directives, and pipes to be exported and permitted to be imported by another modules. The rest is private. This is the module's public API and similar to how the export keyword works in ECMAScript modules.
  • providers: This is the array of services (service classes, factories, or values), which are available in that module. Providers are parts of the module and can be injected into components (inclusive sub-components), directives, and pipes defined within the module.
  • bootstrap: Every Angular application has at least one module--the root module. The bootstrap property is only used in the root module and contains the component which should be instantiated first when bootstrapping the application.
  • entryComponents: This is the array of components that Angular generates component factories for. Normally, you need to register a component as an entry component when it is intended to be created dynamically at runtime. Such components can not be figured out automatically by Angular at template compilation time.

A typical module configuration for any separate example in this book looks something like this:

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {FormsModule} from '@angular/forms';
import {APP_BASE_HREF} from '@angular/common';

// PrimeNG modules needed in this example
import {ButtonModule} from 'primeng/components/button/button';
import {InputTextModule} from 'primeng/components/inputtext/inputtext';

import {AppComponent} from './app.component';
import {SectionComponent} from './section/section.component';
import {routes} from './app-routing.module';

@NgModule({
imports: [BrowserModule, BrowserAnimationsModule, FormsModule,
routes, ButtonModule, InputTextModule],
declarations: [AppComponent, SectionComponent],
providers: [{provide: APP_BASE_HREF, useValue: '/'}],
bootstrap: [AppComponent]
})
export class AppModule { }
BrowserModule is needed to get access to the browser-specific renderers and Angular standard directives such as ngIf and ngFor. Don't import BrowserModule in any other modules except the root module. Feature modules and lazy-loaded modules should import CommonModule instead.

The following is an example of how to bootstrap an Angular application in the JIT mode (just in time compilation):

import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';

platformBrowserDynamic().bootstrapModule(AppModule);

In the ahead-of-time mode (AOT compilation), you need to provide a factory class. To generate the factory class, you must run the ngc compiler instead of the TypeScript tsc compiler. In the last two sections of this chapter, you will see how to use AOT with Webpack and Angular CLI. The bootstrapping code in the AOT mode looks like the following:

import {platformBrowser} from '@angular/platform-browser';
import {AppModuleNgFactory} from './app.ngfactory';

platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
Templates with bindings written in Angular need to be compiled. With AOT, the compiler runs once at build time. With JIT, it runs every time at runtime. Browsers load a pre-compiled version of the application much faster and there is no need to download the Angular compiler if the app is already compiled.

Modules can also be lazy loaded when they get requested (on demand). This approach reduces the size of web resources loaded on initial page display. The page appears faster. If you want to enable lazy loading, you have to configure the router to load the module lazy. All you need is a path object with a loadChildren property, which points to the path and name of the lazy loaded module:

{path: "section", loadChildren: "app/section/section.module#SectionModule"}

Note that the value of loadChildren property is a string. Furthermore, the module importing this router configuration should not declare the lazy loaded module as dependency in the imports property of the configuration object.

Lifecycle hooks

Angular components come with lifecycle hooks, which get executed at specific times in the component's life. For this purpose, Angular offers different interfaces. Each interface has a method of the same name as the interface name with the prefix ng. Each method is executed when the corresponding lifecycle event occurs. They are also called lifecycle hook methods. Angular calls the lifecycle hook methods in the following sequence after the constructor has been called:

The lifecycle hook method Purpose and timing
ngOnChanges This is called whenever one or more data-bound input properties change. This method is called on initial changes (before ngOnInit) and any other subsequent changes. This method has one parameter--an object with keys of type string and values of type SimpleChange. The keys are the component's property names. The SimpleChange object contains current and previous values. A usage example is shown next.
ngOnInit This is called once, after the first ngOnChanges. Note that the constructor of a component should only be used for dependency injection because data-bound input values are not yet set in the constructor. Everything else should be moved to the ngOnInit hook. A usage example is shown next.
ngDoCheck This is called during every change detection run. It is a good place for custom logic, which allows us to do a fine-grained check of which property on our object changed.
ngAfterContentInit This is called once, after Angular puts external content into the component's view. A placeholder for any external content is marked with the ngContent directive (the ng-content tag). A usage example of the ngContent directive is demonstrated afterwards.
ngAfterContentChecked This is called after Angular checks the content put into the component's view.
ngAfterViewInit This is called once, after Angular initializes the component's and child's views.
ngAfterViewChecked This is called after Angular checks the component's views and child views.
ngOnDestroy This is called just before Angular destroys the component's instance. This happens when you remove the component with built-in structural directives such as ngIf, ngFor, ngSwitch, or when you navigate to another view. This is a good place for cleanup operations such as unsubscribing observables, detaching event handlers, canceling interval timers, and so on.

 

Let's see an example of how to use ngOnInit and ngOnChanges:

import {Component, OnInit, OnChanges, SimpleChange} from '@angular/core';

@Component({
selector: 'greeting-component',
template: `<h1>Hello {{text}}</h1>`
})
export class GreetingComponent implements OnInit, OnChanges {
@Input text: string;

constructor() { }

ngOnInit() {
text = "Angular";
}

ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
console.log(changes.text);
// changes = {'text': {currentValue: 'World', previousValue: {}}}
// changes = {'text': {currentValue: 'Angular',
previousValue: 'World'}}
}
}

Usage in HTML:

<greeting-component [text]="World"></greeting-component>

Let's now see how to use the ngContent directive:

export @Component({
selector: 'greeting-component',
template: `<div><ng-content></ng-content> {{text}}</div>`
})
class GreetingComponent {
@Input text: string;
}

Usage in HTML:

<greeting-component [text]="World"><b>Hello</b></greeting-component>

After the component's initialization, the following hook methods get always executed on every change detection run: ngDoCheck -> ngAfterContentChecked -> ngAfterViewChecked -> ngOnChanges.

Running PrimeNG with SystemJS

PrimeNG (https://www.primefaces.org/primeng) is an open source library of rich UI components for Angular 2+. PrimeNG is derived from PrimeFaces--the most popular JavaServer Faces (JSF) component suite. If you know PrimeFaces, you will feel at home with PrimeNG due to similar API. Currently, PrimeNG has 80+ visually stunning widgets that are easy to use. They are divided into several groups such as input and select components, buttons, data iteration components, panels, overlays, menus, charts, messages, multimedia, drag-and-drop, and miscellaneous. There are also 22+ free and premium themes.

PrimeNG fits perfectly with the mobile and desktop development because it is a responsive and touch optimized framework. PrimeNG showcase is a good place to play with the components, try them in action, study documentation, and code snippets. Anyway, we need a systematic approach for getting started with PrimeNG. This is what this book tries to convey. In this chapter, we will set up and run PrimeNG with SystemJS (https://github.com/systemjs/systemjs)--universal module loader supporting various module formats. SystemJS is a good choice for learning purposes if you want to try TypeScript, Angular, PrimeNG code snippets, or write small applications in Plunker (https://plnkr.co) because it can load your files, transpile them (if needed) and resolve module dependencies on-the-fly. In the real applications, you should choose Webpack or Angular CLI-based setups that have more power and advanced configurations. They also bundle your application in order to reduce the amount of HTTP requests. Those setups will be discussed in the next two sections.

The SystemJS configuration for Angular

First of all, you need to install Node.js and npm, which we already mentioned in the TypeScript fundamentals you need to know section. Why do we need npm? In HTML and SystemJS configuration, we could reference all dependencies from https://unpkg.com. But, we prefer to install all dependencies locally so that IDEs are fine with autocompletion. For instance, to install SystemJS, you have to run the following command in a console of your choice:

npm install systemjs --save

For readers, we created a complete demo seed project where all dependencies are listed in the package.json file.

The complete seed project with PrimeNG and SystemJS is available on GitHub at
https://github.com/ova2/angular-development-with-primeng/tree/master/chapter1/primeng-systemjs-setup.

All dependencies in the seed project can be installed by running npm install in the project root. If you explore the index.html file, you can see that the SystemJS library is included in the <head> tag. After that, it becomes available as a global System object, which exposes two static methods: System.import() and System.config(). The first method is used to load a module. It accepts one argument--a module name, which can be either a file path or a logical name mapped to the file path. The second method is used for setting configuration. It accepts a configuration object as an argument. Normally, the configuration is placed within the systemjs.config.js file. Complete scripts to be included in index.html are TypeScript compiler, Polyfills, and SystemJS related files. The bootstrapping occurs by executing System.import('app'):

<script src="../node_modules/typescript/lib/typescript.js"></script>
<script src="../node_modules/core-js/client/shim.min.js"></script>
<script src="../node_modules/zone.js/dist/zone.js"></script>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../systemjs.config.js"></script>

<script>
System.import('app').catch(function (err) {
console.error(err);
});
</script>

An excerpt from the configuration object for Angular projects is listed here:

System.config({
transpiler: 'typescript',
typescriptOptions: {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
map: {
'@angular/animations':
'node_modules/@angular/animations/bundles/animations.umd.min.js',
'@angular/common':
'node_modules/@angular/common/bundles/common.umd.min.js',
'@angular/compiler':
'node_modules/@angular/compiler/bundles/compiler.umd.min.js',
'@angular/core':
'node_modules/@angular/core/bundles/core.umd.min.js',
'@angular/forms':
'node_modules/@angular/forms/bundles/forms.umd.min.js',
...
'rxjs': 'node_modules/rxjs',
'app': 'src'
},
meta: {
'@angular/*': {'format': 'cjs'}
},
packages: {
'app': {
main: 'main',
defaultExtension: 'ts'
},
'rxjs': {main: 'Rx'}
});

A brief explanation gives an overview of the most important configuration options:

  • The transpiler option specifies a transpiler for TypeScript files. Possible values are typescript, babel, and traceur. The transpilation happens in browser on-the-fly.
  • The typescriptOptions option sets the TypeScript compiler options.
  • The map option creates aliases for module names. When you import a module, the module name is replaced by an associated value according to the mapping. In the configuration, all entry points for Angular files are in UMD format.
  • The packages option sets meta information for imported modules. For example, you can set the main entry point of the module. Furthermore, you can specify default file extensions to be able to omit them when importing.

Adding PrimeNG dependencies

Every project using PrimeNG needs the locally installed library. You can achieve this by running the following command:

npm install primeng --save

As a result, PrimeNG is installed in your project root under the node_modules folder as well as added in package.json as a dependency. Here again, you can skip this step if you use the seed project hosted on GitHub--just run npm install. The next step is to add two new entries to the SystemJS configuration file. For shorter import statements, it is recommended to map primeng to node_modules/primeng. PrimeNG components are distributed as CommonJS modules ending with .js. That means we should set the default extension too:

System.config({
...
map: {
...
'primeng': 'node_modules/primeng'
},
packages: {
'primeng': {
defaultExtension: 'js'
},
...
}
});

Now, you are able to import PrimeNG modules from primeng/primeng. For instance, write this line to import AccordionModule and MenuItem:

import {AccordionModule, MenuItem} from 'primeng/primeng';

This way of importing is not recommended in production because all other available components will be loaded as well. Instead of that, only import what you need using a specific component path:

import {AccordionModule} from 'primeng/components/accordion/accordion';
import {MenuItem} from 'primeng/components/common/api';

In the demo application, we will only use ButtonModule and InputTextModule so that we need to import them as follows:

import {ButtonModule} from 'primeng/components/button/button';
import {InputTextModule} from 'primeng/components/inputtext/inputtext';

The demo project we want to create consists of application code and assets. A detailed description of every file would go beyond the scope of this book. We will only show the project structure:

A typically PrimeNG application needs a theme. We would like to take the Bootstrap theme. The file index.html must have three CSS dependencies included within the <head> tag--the theme, the PrimeNG file, and the FontAwesome file for SVG icons (http://fontawesome.io):

<link rel="stylesheet" type="text/css"
href="../node_modules/primeng/resources/themes/bootstrap/theme.css"/>
<link rel="stylesheet" type="text/css"
href="../node_modules/primeng/resources/primeng.min.css"/>
<link rel="stylesheet" type="text/css"
href="src/assets/icons/css/font-awesome.min.css"/>

All FontAwesome files were placed under src/assets/icons. Mostly PrimeNG components are native, but there is a list of components with third-party dependencies. These are explained in the following table:

Component Dependency
Schedule FullCalendar and Moment.js
Editor Quill editor
GMap Google Maps
Charts Charts.js
Captcha Google Recaptcha

 

Exact links to those dependencies will be shown later in concrete examples. For now, we have finished our setup. Let's start our first application by running npm start in the project root.

The application gets launched in browser with two PrimeNG components, as shown in the following screenshot. As you can see, a lot of single web resources (CSS and JS files) are being loaded in the browser:


Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Detailed insights into PrimeNG concepts, components and features with examples to help you make excellent User Interfaces for Angular web apps.
  • Get familiar with themes, layouts and customization in real world applications.
  • Develop Angular applications rapidly using advance tools and standards with best practices.

Description

PrimeNG is a leading UI component library for Angular applications with 80+ rich UI components. PrimeNG was a huge success in the Angular world and very quickly. It is a rapidly evolving library that is aligned with the last Angular release. In comparison with competitors, PrimeNG was created with enterprise applications in mind. This book provides a head-start to help readers develop real–world, single-page applications using the popular development stack. This book consists of 10 chapters and starts with a short introduction to single-page applications. TypeScript and Angular fundamentals are important first steps for subsequent PrimeNG topics. Later we discuss how to set up and configure a PrimeNG application in different ways as a kick-start. Once the environment is ready then it is time to learn PrimeNG development, starting from theming concepts and responsive layouts. Readers will learn enhanced input, select, button components followed by the various panels, data iteration, overlays, messages and menu components. The validation of form elements will be covered too. An extra chapter demonstrates how to create map and chart components for real-world applications. Apart from built-in UI components and their features, the readers will learn how to customize components to meet their requirements. Miscellaneous use cases are discussed in a separate chapter, including: file uploading, drag and drop, blocking page pieces during AJAX calls, CRUD sample implementations, and more. This chapter goes beyond common topics, implements a custom component, and discusses a popular state management with @ngrx/store. The final chapter describes unit and end-to-end testing. To make sure Angular and PrimeNG development are flawless, we explain full-fledged testing frameworks with systematic examples. Tips for speeding up unit testing and debugging Angular applications end this book. The book is also focused on how to avoid some common pitfalls, and shows best practices with tips and tricks for efficient Angular and PrimeNG development. At the end of this book, the readers will know the ins and outs of how to use PrimeNG in Angular applications and will be ready to create real- world Angular applications using rich PrimeNG components.

Who is this book for?

This book is for everybody who would like to learn or create modern Angular based single page applications using PrimeNG component library. This book is a good choice for beginners to advanced users who are serious to learn modern Angular applications. The prerequisites for this book are some basic knowledge on the Angular 2+ version with TypeScript and CSS skills.

What you will learn

  • - Setup PrimeNG projects with SystemJS, Webpack, and Angular CLI.
  • - Use theming concepts and layouts with grid systems and Bootstrap.
  • - Work with enhanced input, select, button and panel components.
  • - Apply countless DataTable features: sorting, filtering, grouping, and templating.
  • - Meet data iteration components: DataList, DataGrid, Tree, and so on.
  • - Build endless menu variations: SlideMenu, TieredMenu, MegaMenu, and so on.
  • - Visualize your data representations with PrimeNG charts and GMap components.
  • - Adopt best practices such as state management with @ngrx/store.
  • - Write unit and end-to-end tests with Jasmine, Karma, and Protractor.
Estimated delivery fee Deliver to India

Premium delivery 5 - 8 business days

₹630.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jul 27, 2017
Length: 384 pages
Edition : 1st
Language : English
ISBN-13 : 9781788299572
Vendor :
Google
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
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
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to India

Premium delivery 5 - 8 business days

₹630.95
(Includes tracking information)

Product Details

Publication date : Jul 27, 2017
Length: 384 pages
Edition : 1st
Language : English
ISBN-13 : 9781788299572
Vendor :
Google
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
₹800 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
₹4500 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 ₹400 each
Feature tick icon Exclusive print discounts
₹5000 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 ₹400 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 14,450.97
Angular UI Development with PrimeNG
₹3649.99
Expert Angular
₹4096.99
Bootstrap 4 ??? Responsive Web Design
₹6703.99
Total 14,450.97 Stars icon

Table of Contents

10 Chapters
Getting Started with Angular and PrimeNG Chevron down icon Chevron up icon
Theming Concepts and Layouts Chevron down icon Chevron up icon
Enhanced Inputs and Selects Chevron down icon Chevron up icon
Button and Panel Components Chevron down icon Chevron up icon
Data Iteration Components Chevron down icon Chevron up icon
Amazing Overlays and Messages Chevron down icon Chevron up icon
Endless Menu Variations Chevron down icon Chevron up icon
Creating Charts and Maps Chevron down icon Chevron up icon
Miscellaneous Use Cases and Best Practices Chevron down icon Chevron up icon
Creating Robust Applications Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Half star icon Empty star icon Empty star icon 2.3
(3 Ratings)
5 star 33.3%
4 star 0%
3 star 0%
2 star 0%
1 star 66.7%
David Lastovicka Jan 27, 2018
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I am a professional software developer with a lot of experience in web applications development. Only recently I started to learn Angular, Typescript and I chose PrimeNG as a component library to implement GUI.The book Angular UI development with PrimeNG turned out to be just perfect for someone with my profile: for a person with previous experience in web development but new to Angular and PrimeNG.Before reading the book I went through Angular, Typescript and PrimeNG tutorials and I thought that I got a fair knowledge so that I could create a skeleton of my first application.Yet, thanks to the book I got could fill many gaps on the level of Typescript (e.g. type assertions, decorators), Angular (e.g. communication between components, built-in directives overview, ng templates, forms) and I learned about CSS theming and layouts, automated tests and got understanding of the application setup. The section related to PrimeNG components disappointed me because it overlaps a lot with the web documentation, although there were cases where the additional comments helped me to put PrimeNG components into use more quickly.The book is neither meant for a complete beginner in the web application development, nor does it offer a very deep insight into the libraries background and I can imagine that some readers may be disappointed: complete web development beginners or professionals with a solid Angular and Typescript knowledge. For me the book met the expectations and directly contributed to improving my project.
Amazon Verified review Amazon
J. L. Hallock Nov 17, 2017
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
The documentation on the PrimeNG website is far better than this book. While all the elements are listed in the book, only a couple pages are devoted to each one. Honestly a VERY big waste of money.
Amazon Verified review Amazon
Rob Schripsema Jun 11, 2018
Full star icon Empty star icon Empty star icon Empty star icon Empty star icon 1
The book tries to do too much, and does none of it well. Way too many pages devoted to fundamentals of Angular that could have better been given to the PrimeNg components. The information available on the PrimeNg website is FAR more comprehensive and usable.Also needs a good editor, as there are numerous grammatical gaffes that make it difficult to take seriously.
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 digital copy I get with my Print order? Chevron down icon Chevron up icon

When you buy any Print edition of our Books, you can redeem (for free) the eBook edition of the Print Book you’ve purchased. This gives you instant access to your book when you make an order via PDF, EPUB or our online Reader experience.

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