Book Image

Expert Angular

By : Sridhar Rao Chivukula
Book Image

Expert Angular

By: Sridhar Rao Chivukula

Overview of this book

Got some experience of Angular under your belt? Want to learn everything about using advanced features for developing websites? This book is everything you need for the deep understanding of Angular that will set you apart from the developer crowd. Angular has introduced a new way to build applications. Creating complex and rich web applications, with a lighter resource footprint, has never been easier or faster. Angular is now at release 4, with significant changes through previous versions. This book has been written and tested for Angular release 4. Angular is a mature technology, and you'll likely have applications built with earlier versions. This book starts by showing you best practices and approaches to migrating your existing Angular applications so that you can be immediately up-to-date. You will take an in-depth look at components and see how to control the user journey in your applications by implementing routing and navigation. You will learn how to work with asynchronous programming by using Observables. To easily build applications that look great, you will learn all about template syntax and how to beautify applications with Material Design. Mastering forms and data binding will further speed up your application development time. Learning about managing services and animations will help you to progressively enhance your applications. Next you’ll use native directives to integrate Bootstrap with Angular. You will see the best ways to test your application with the leading options such as Jasmine and Protractor. At the end of the book, you’ll learn how to apply design patterns in Angular, and see the benefits they will bring to your development.
Table of Contents (18 chapters)

Angular architecture

Before we discuss architecture, let's see what's new in Angular. The primary focus of Angular is mobiles, as it is important to consider the performance and loading time of the application on a mobile phone. Many modules are decoupled from the Angular core, leaving only the modules that are definitely core; removing unwanted modules from Angular core leads to better performance.

Angular targets ES6 and leverages TypeScript as a development script language that enables compile time checks for types, rather than at runtime. TypeScript provides additional information about classes when instantiating them by annotating metadata to the classes. You can also use ES5 and Dart as the development language. There is an improved version of Dependency Injection that supports child injectors and instance scope. Router was rewritten completely and the component router was introduced. The Component Directive, the Decorator Directive, and the Template Directive are supported in Angular. The $scope has been completely removed from Angular.

The architecture of Angular comprises Modules, Components, Templates, Metadata, Directives, and Services:

NgModules

Angular framework has various libraries that are grouped as modules in order to build an application. Angular applications are modular in nature and are constructed by assembling various modules. Modules may have components, services, functions, and/or values. Some modules may have a collection of other modules and are known as library modules.

Angular packages, such as core, common, http, and router that are prefixed with @angular comprise many modules. We import what our application needs from these library modules as follows:

import {Http, Response} from @angular/http'; 

Here, we import Http and Response from the library module, @angular/http. @angular/http refers to a folder in the Angular package. Any module defined to be exported can be imported into another module by referring to the filename of the module.

Note: this import statement was introduced in ES2015 and is used to import objects or function that are exported from other modules or scripts


However, we can also refer to the folder as we referred to @angular/http. This can be achieved by adding an index.ts file to the folder and adding the code to export modules from the folder. This is a best practice suggested by Angular's style guide and is called the barrel technique:

export * from './http'; 

This is the export statement in the index.ts found in @angular/http. The statement means that it exports all the modules in HTTP and that they can be imported to our application wherever needed.

When we write an Angular application, we start by defining an AppComponent (not necessarily with the same name) and exporting it.

Components

A component is a class that has properties and methods to be used in the view. These properties and methods exposed to view enable the view to interact with components. We code logic that supports the view in the component class:

For example, next is a component class book that has a properties title and author and a getPubName method that returns the name of the book:

export class BookComponent { 
  title: string; 
  author: string; 
  constructor() { 
      this.title = 'Learning Angular for .Net Developers'; 
      this.author = 'Rajesh Gunasundaram'; 
  } 
  getPubName() : string { 
    return 'Packt Publishing'; 
  } 
} 
Note: We will be using TypeScript in all our examples in this book.

The life cycle of a component is managed by Angular according to user interactions with the application. We can also add an event method that will be fired according to the state changes of the component. These event methods are known as life cycle hooks and are optional.

We will learn in detail about components in Chapter 5, Implementing Angular Routing and Navigation.

Templates

Templates can be thought of as a representation of a component that is visualized according to the UI/UX needs of an application. A component will have a template associated with it. The template is responsible for displaying and updating data according to user events:

Here is a simple template that displays the title and author of a book:

<h1>Book Details</h1> 
<p>Title of the Book: {{title}}</p> 
<p>Author Name : {{author}}</p> 

Here, the title and author values wrapped in curly braces will be supplied by the associated component instance.

We will discuss templates and their syntax in detail in Chapter 8, Template and Data Binding Syntax.

Metadata

A class can be turned into a component by annotating it with @Component and passing the necessary metadata, such as selector, template, or templateUrl. Angular considers a class as a component only after attaching metadata to it:

Let's revisit the BookComponent class we defined earlier. Angular does not consider this class as a component unless we annotate it. TypeScript leverages the ES7 feature by providing a way to decorate a class with metadata as follows:

@Component({ 
  selector:    'book-detail', 
  templateUrl: 'app/book.component.html' 
}) 
export class BookComponent { ... } 

Here, we have decorated the BookComponent class with @Component and attached metadata selector and templateUrl. It means that, wherever Angular sees the special <book-detail/> tag in the view, it will create an instance of BookComponent and render the view assigned to templateUrl, which is book.component.html.

A decorator provided by TypeScript is a function that takes configuration parameters that are used by Angular to create an instance of the component and render the associated view. Configuration parameters may also have information about directives and providers, which will be made available by Angular when the component is created.

Data Binding

Data Binding is one of the core responsibilities of developers when writing code to bind data to the user interface and update changing data according to user interactions with the user interface. Angular has reduced the burden of writing large amounts of code to handle Data Binding:

Angular handles Data Binding by coordinating with templates and components. The templates provide instructions to Angular on how and what to bind. There are two types of binding in Angular: globally One-way Data Binding and Two-way Data Binding. One-way Data Binding deals with either binding data from the component to the DOM or from the DOM to the component. Two-way Data Binding deals with both sides of communication, that is, the component to the DOM and the DOM to the component.

<div>Title: {{book.title}}<br/> 
  Enter Author Name: <input [(ngModel)]="book.author"> 
</div> 

Here, book.title wrapped in double curly braces deals with One-way Data Binding. The value of book title, if available in the component instance, will be displayed in the view. book.author, assigned to the ngModel property of the input element, deals with Two-way Data Binding. If the component instance has a value in the author property, then it will be assigned to the input elements, and if the value is changed by the user in the input control, then the updated value will be available in the component instance.

We will learn in detail about Data Binding in Chapter 8, Template and Data Binding Syntax.

Directives

A directive is instructions or guidelines for rendering a template. A class decorated with @Directive to attached metadata is called a directive. There are three types of directive supported by Angular, namely Component Directive, Structural Directive, and Attribute Directive:

A component is one form of a directive with a template that is decorated with @Component: it is actually an extended @Directive with a template feature:

<book-detail></book-detail> 

Structural Directives manipulate the DOM elements and alter their structure by adding, removing, and replacing DOM elements. The following code snippet uses two Structural Directives:

<ul> 
<li *ngFor="let book of books"> 
    {{book.title}} 
</li> 
</ul> 

Here, the div element has a *ngFor directive that iterates through the books collection object and replaces the title of each book.

An Attribute Directive helps to update the behavior or the appearance of an element. Let's use the Attribute Directive to set the font size of a paragraph. The following code snippet shows an HTML statement implemented with an Attribute Directive:

<p [myFontsize]>Fontsize is sixteen</p> 

We need to implement a class annotated with @Directive along with the selector for the directive. This class should be implemented with the instructions on the behavior of the directive:

import { Directive, ElementRef, Input } from '@angular/core'; 
@Directive({ selector: '[myFontsize]' }) 
export class FontsizeDirective { 
    constructor(el: ElementRef) { 
       el.nativeElement.style.fontSize = 16; 
    } 
} 

Here, Angular will look for elements with the [myFontsize] directive and sets the font size to 16.

It is necessary to pass the myFontSize directive to the declarations metadata of @NgModule as follows:

import { NgModule } from '@angular/core'; 
import { BrowserModule } from '@angular/platform-browser'; 
import { AppComponent } from './app.component'; 
import { FontsizeDirective } from './fontsize.directive'; 
@NgModule({ 
  imports: [ BrowserModule ], 
  declarations: [ 
    AppComponent, 
    FontsizeDirective 
  ], 
  bootstrap: [ AppComponent ] 
}) 
export class AppModule { } 

We will discuss directives in detail in Chapter 6, Creating Directives and Implementing Change Detection.

Services

Services are user-defined classes used to solve problems. Angular recommends only having template-specific codes in components. A component's responsibility is to enrich the UI/UX in the Angular application and delegate business logic to services. Components are consumers of services:

Application-specific or business logic such as persisting application data, logging errors, and file storage should be delegated to services, and components should consume the respective services to deal with the appropriate business or application-specific logic:

For example, we can have a service called BookService that deals with inserting new books, editing or deleting existing books, and fetching a list of all the books available.

We will see more about services in Chapter 11, Implementing Angular Pipes.

Dependency Injection

When an instance of a class is created, supplying the required dependencies of that class for it to function properly is called Dependency Injection. Angular provides a modern and improved version of Dependency Injection:

In Angular, the injector maintains the containers to hold the instances of the dependencies and serves them as and when required. If the instance of a dependency is not available in the container, then the injector creates an instance of the dependency and serves it:

As stated earlier, components have logic that is related to templates and mostly consume services to perform business logic. So, components depend on services. When we write code for components, we create a parameter constructor that takes the service as an argument. It means that creating an instance of the component depends on the service parameter in the constructor. Angular requests that the injector provide the instance of the service in the parameter of the constructor of the component. The injector will serve the instance of the requested service, if available; otherwise, it creates a new one and serves it:

export class BookComponent { 
  constructor(private service: BookService) { } 
} 

In this code snippet, the : symbol comes from TypeScript and is not Angular syntactical sugar. The private keyword is also from TypeScript and enables assigning the passed constructor to the class instance automatically. The type information is used to infer the type to be injected. The BookComponent has a dependency to BookService and is injected in the constructor. So when an instance of the BookComponent is created, Angular will also make sure the instance of BookService is readily available for the BookComponent instance to consume.

The injector has knowledge of the dependencies to be created from providers that are configured with the required dependency types when bootstrapping the application or when decorating the components, as follows:

@NgModule({ 
  imports: [BrowserModule], 
  declarations: [AppComponent,], 
  providers: [BookService], 
  bootstrap: [ AppComponent ] 
}) 
export class AppModule { } 

The preceding code snippet adds BookService as a provider to the bootstrap function. The injector will create an instance of BookService and keep it available in the container for the entire application to inject whenever it's requested:

@Component({ 
  providers:   [BookService] 
}) 
export class BookComponent { ... } 

The preceding code snippet adds BookService as a provider in the metadata of the component. The injector will create an instance of BookService when it encounters a request to create an instance of BookComponent.

We will discuss Dependency Injection and hierarchical Dependency Injection in detail in
Chapter 12
, Implementing Angular Services.