K.Srivatsan - vatsank@gmail.
com
• IT Trainer Since 1991
• Conducting Java Training Since 2004
• About 50+ Corporate Clients
HTTP://BIT.LY/ANG4_VATSAN
GITHUB.COM/VATSANK
Topics
• Angular Introduction
• Angular Branding
• Single Page and Multi Page Application
• MVC Pattern
Angular
• A platform that makes it easy to build applications with the web.
• It combines declarative templates, dependency injection, end to
end tooling
• Integrated best practices to solve development challenges.
• Empowers developers to build applications that live on the web,
mobile, or the desktop
AngularJs -1.x
• A JavaScript-based front-end web application framework
– maintained by Google
• Helps developing single-page applications.
• Simplifies both the development and the testing of applications
– by providing a framework for client-side
– model–view–controller (MVC)
– model–view–viewmodel (MVVM) architectures
– Also components commonly used in rich Internet applications.
AngularJS 1.x
• Works by first reading the HTML page, which has embedded into it
additional custom tag attributes.
• Interprets those attributes as directives to bind input or output parts
of the page to a model that is represented by standard JavaScript
variables.
• The values of those JavaScript variables can be manually set within
the code, or retrieved from static or dynamic JSON resources.
• Its is the frontend part of the MEAN stack
– MongoDB database,
– Express.js web application server framework,
– Angular.js itself,
– Node.js server runtime environment.
Angular 2
• Angular 2 successor to Angular 1 than a “update.”
– The final version was released on September 14, 2016
• Component based without any controllers or scopes.
– Much Cleaner and has removed most of the directives found in
Angular1
• Uses strongly typed language
– Extended version of TypeScript annotations decorators
Angular1.X vs Angular 2
• Angular 2 shares some concepts with its predecessor
– the special HTML templating syntax,
– directives/components to modify the DOM
• Has Introduced better strategies and concepts to improve the
performance
– By updating data binding concept.
• Angular 1 may not be deprecated or will not lack support
– It will be there to stay
• Angular 2 is Well designed and its is mobile oriented.
– Need for Iconic framework is minimized
Version History
Angular 2 14th Sep 2016
Angular 4 23rd March 2017
Angular 5 11th Nov 2017
Angular 6 03rd May 2018
Angular 2
• Dropped controllers - uses component-based UI
– Instead of binding to properties in the scope they are directly bound to
the components
– Uses the ES6 modules.
– Similar to ReactJS.
• Routers
– Enhanced Routing
– Feature rich than the old ngRoute
Angular 4
• Released on March 23, 2017.
– Skipping 3 to avoid a confusion due to the misalignment of the router
package's version which was already distributed as v3.3.0
– Angular 4 is backward compatible with Angular 2.
• Smaller & Faster
– Angular applications becomes smaller and faster.
• View Engine
– AOT generated code reduce the size of the generated code by around
60%
– More complex the templates the higher the savings.
– Migrating to 4 reduced production bundles by hundreds of kilobytes.
What is New angular 4
• Animation Package
– Animations is removed from @angular/core and into their own package.
– Added by importing @angular/platform-browser/animations.
• Improved *ngIf
– Can now use an if/else style syntax
• TypeScript 2.1 and 2.2 compatibility
– Updated to a more recent version of TypeScript.
– Improve the speed of ngc
– Better type checking in application.
• Source Maps for Templates
– When there is an error caused by something in templates
– A Source Map is generated that give a meaningful context in terms of
the original template.
Angular 5
• Angular 5 was released on November 1, 2017.
• Key improvements in Angular 5
– Support for progressive Web apps,
– A build optimizer that makes the application smaller by eliminating
unnecessary code.
– Pipes for internationalized number, date, and currency.
– Run validation and value updates on blur and submit rather than on
every input event.
Angular - Architecture
• The architecture of Angular 2 contains following modules:
– Module
– Component
– Template
– Metadata
– Data Binding
– Service
– Directive
– Dependency Injection
Single Page Applications
• Writing large-scale, maintainable single-page-applications are big
challenge.
– fixing bugs, writing unit tests and creating reusable chunks of code…
• Single-page-applications with older frameworks gies different ways
to design an application.
– There wasn’t any structure, encapsulation and everything was tightly
coupled to each other.
• SPA-technologies like Angular make use components.
– With a predefined structure and encapsulation
Single Page Application
• HTML is a great declarative language for static documents.
– It does not contain much in the way of creating applications,
• One "real" HTML page whose content can be changed in Javascript
without having to download a new page.
– The new content is created programmatically using templates.
– Server sends an application engine along with the HTML page
• The engine controls the entire application including
processing, input, output, painting, and loading of the HTML
pages.
• Server is used when there is a need for new data or must perform secured
operations such as authentication.
Characteristics Single Page Application:
• Chunking
– Pages are constructed by loading chunks of HTML fragments and
JSON data instead of receiving full HTML from server on every request.
• Controllers
– JavaScript code that handles complex DOM and data manipulations,
application logic and AJAX calls is replaced by controllers that separate
views and models using MVC or MVVM patterns.
• Templating
– coding of UI and DOM manipulations are replaced by declarative
binding of data to HTML templates.
• Routing
– selection of views and navigation (without page reloads) that preserves
page state, elements and data
MVC on Client Side
• Client side MVC
– MVC framework is built entirely on the client side.
– Server only delivers data to the application.
– The binding of the data to the models happens client side.
• Need for client-side MVC
– operations are not only with HTML but with data on the page.
– when data is collection of JSON
– Process data, perform all required calculations, render HTML and
put that into page.
– CRUD actions , over REST API.
– adding or deleting should not make page to reload
– can update page according to current data state.
MVC on Server Side
MVC on Client Side
MVC in Angular
• Angular is more of component based architecture.
– A well defined component consist of individual set of MVC architecture.
• Model will mostly uses services, which is accessed through
Components
– A Simple class file can also be called Model.
• component.html
– These are the view
– The HTML, is what is presented to the user (along with some CSS for
layout). It is easy to see how this represents the view.
• component.ts
– Is the controller .
– It can choose which data to push to view
– Has difference forms of binding
Single Page Application in Angular
• Single Page application have many MVC relationships
• MVC’S be side by side
• A user can navigate from one page to another
• MVC can be nested
• Example : In a Hotel Application
– We can components for
– Reservation
– front desk
– room service
– catering
• Each one of them MVC on its own
Angular 4 Dependency
• Introduction to NodeJs
• Introduction to Es6
• Introduction to Type Script
Choosing a Module Loader
• Module bundling.
– Module loader takes a group of modules with their dependencies and
merges them into a single file in the correct order.
• Having <script> tag loads files is inefficient as it reduces the page
speed as the browser requests each file separately.
• Can bundle several files together into one big file.
• The entire file can be downloaded in one single request reducing
the number of requests.
• Can also minify the file (remove the extra spaces,comments,
unnecessary characters etc) and make files smaller
Choosing a Module Loader
• The two popular Module loaders are Webpack and SystemJS
• Webpack is a more flexible module bundler than SystemJS.
• It can not only bundle modules but also minifies our modules.
• It also comes with a development server with hot module
replacement option.
• The Angular CLI project has moved to Webpack from the
SystemJS.
Webpack
• Webpack is a powerful module loader.
• It takes modules with dependencies and generates static assets
representing those modules.
• Webpack has the ability to bundles any kind of file: JavaScript,
TypeScript, CSS, SASS, LESS, images, HTML, fonts etc.
• The clever parser that can process nearly every 3rd party library.
Webpack Dev Server
• The Webpack also comes with a development server.
• Can be used run application as we are developing the application.
• The Development server uses the Webpack’s watch mode.
• Any changes made to our application are instantly updated.
• Configured by using the webpack.config.js. Configuration file
Angular Development Environment
• Installing Angular CLI
• Done by using the following command.
• npm install -g @angular/cli
• ng -version
• Creating the Project
– Created by executing the following command from the Prompt
– ng new “gettingstarted”
– Creates a folder gettingstarted and copies all the required files
and configuration settings.
Angular - Architecture
Angular Application Folder structure
• Creates a Sample Angular Application
• It contains the subfolders e2e, node_modules and src.
• It also contains the few configuration files
• Angular.json
– This is the configuration file for Angular CLI
• karma.conf.json
– The Configuration file karma test runner. Angular uses the
Jasmine as the testing framework
• protractor.conf.js
– The Configuration file for protractor end to end test runner.
• tslint.json
– tslint is a static code analysis tool used in software development for checking
Typescript code quality.
•
Packages.json
• It also creates a packages.json which contains dependencies
{
"name": "quickstart",
"version": "0.0.0",
"scripts": {
},
"dependencies": {
},
"devDependencies": {
}
}
Packages.json
• Script Section
– This Script section contains many of the most useful
commands
– Ng,start,test etc
• devDependencies Section
– This section contains the entries required for application
development
– Typescript,karma,jasmine,protractor etc.,
Updating Package.json
• Can also add in Project’s package.json and run update
"dependencies": {
"bootstrap": “^4.1.2”
},
npm install
[email protected] --save
• Import the Bootstrap.min.css to style.css
– @import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
Sample Application
• app/app.component.ts
– where root component is defined
• app/app.component.css
– where Css Styles are defined
• app/app.component.html
– where HTML templates are defined
• app/app.component.spec.ts
– where Test Specification are defined
• app/app.module.ts
– - the entry Angular Module to be bootstrapped
• index.html
– this is the page the component will be rendered in
• app/main.ts
– - is the glue that combines the component and page together
@Component decorator
• Components are decorated with @Component decorator.
• Provides Metadata about component
• It consists of three main parts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
Export and Import Component
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
}
app/app.component.html
<div style="text-align:center">
<h1>
Welcome to {{title}}!!
</h1>
</div>
app/app.module.ts
• The Angular applications are organized as modules.
– application must have at least one module.
– root Module is loaded first
• Reference of root component type is passed as argument
– Its called as root module
• Application routes declarations should be done here
NgModule
• Modules are class decorated with the @NgModule
• Decorator function which has one argument
– A metadata object with properties describing the module.
• Some of its important properties are:
• Bootstrap Array
• Export Array
• Import Array
• Provider Array.
Modules
• Bootstrap array
– Used to inform which components need to be loaded, so that its
functionality can be accessed in the application.
• Export array
– Used to export components, directives, and pipes which can then be
used in other modules.
• Import array
– Used to import the functionality from other modules.
• Providers array
– Used to provide the services by the module
Modules
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CreditCardModule } from '../credit-card/credit-card.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule, CreditCardModule ],
declarations: [AppComponent],
bootstrap: [AppComponent] })
export class AppModule { }
app/main.ts
• Makes angular to load the AppModule and controls the start up of
the application
• bootstrapModule method of platformBrowserDynamic library
– to bootstrap AppModule
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { environment } from './environments/environment';
import { AppModule } from './app/app.module';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
app.main.ts
• platformBrowserDynamic library.
– Contains the functions required to bootstrap the angular application.
• enableProdMode from @angular/core library.
– The Angular’s code by default runs in development mode.
– The development mode runs few assertions and checks
– helps in debugging the application.
index.html
<html>
<head>
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
• The selector “app-root”, defined in component metadata is used as
HTML tag.
• Angular scans the HTML page for <app-root>
– replaces the entire content with content of app.component.html
Running Angular Application
• npm start
– will run definitions of the start command of the scripts object in package.json file.
– Compiles the Angular application and invokes the Webpack development server.
– Watches project folder and if any changes are made it compiles the project again.
– Server listens on HTTP Port 4200.
– http://localhost:4200/
• Can Change the Default Port using angular-cli.json
"defaults": {
"styleExt": "css",
"component": {},
"serve": {
"port": 5200
}
}
Ng-serve
• ng serve
– command launches the server,
– Watches files, and rebuilds the app
– serves an Angular project via a development server
• Using the --open or -o option
– will automatically open browser on http://localhost:4200/.
The Component
• Angular migrated from directives to components
– Directives that are always associated with a direct template.
• They represent the view of the application.
• Can have methods and properties, which supply logic to view.
• Smart / Container components
– application-specific, higher-level, container components, with access to
the application's domain model.
• Dumb / Presentational components
– components responsible for UI rendering and/or behavior of specific
entities passed in via component properties and events
Generating Components
• ng generate or ng g
• Ng generate component footer
• ng g component my-new-component
• ng g component feature/new-cmp
• Creating a new component, generates the following files
– component.html (View)
– component.ts (Controller)
• ng generate --help
– To View all available options Angular CLI.
Angular CLI commands
• Directive
ng g directive my-new-directive
ng g d my-new-directive
• Pipe
ng g pipe my-new-pipe
ng g p my-new-pipe
• Service
ng g service my-new-service
ng g s my-new-service
• Class
ng g class my-new-class
ng g cl my-new-class
• Interface
– ng g interface my-new-interface
Angular CLI commands
• To skip npm install
--skip-install: boolean
default false
• To Add Routing Information and import in main app
--routing: boolean,
default false,
Assets
• Static Files like images and styles are served from assets folder
• src/assets/css and copy the styles.css to it.
• src/assets/images and copy the images to it
Component Class
• The basic building block of an UI
– An application is a tree of components.
• Component decorator marks a class as an Angular component
• A component must belong to an NgModule in order for it to be
usable by another component or application.
• Component Class has a constructor() to setup Dependency
Injection
• Components can control their runtime behavior by implementing
various Life-Cycle hooks.
Configuring More than One Component
Done in the app.module.ts
import { AppComponent } from './app.component';
import { HeaderComponent } from './app.headercomponent';
@NgModule({
declarations: [
AppComponent,
HeaderComponent,
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent,HeaderComponent]
})
export class AppModule { }
Header Component
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
banner: string;
constructor() {
this.banner = 'assets/images/Banner.jpg';
}
ngOnInit() { }
}
Data Binding - Interpolation
• communication between a component and it’s Template
– {{ expression }} to render the bound value to the component’s
template.
– To weave calculated strings into the text between
• HTML element tags and within attribute assignments.
– Replaces the name with the string value of the corresponding
component property
<img src={{banner}} class='banner' />
Index.html
<!doctype html>
<html lang="en">
<head>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-header> </app-header>
<app-root> </app-root>
</body>
</html>
TEMPLATES
Angular Templates
• Templates mix native HTML with custom elements.
• Inline Templates
– Specified directly in the component decorator
– Template literals with back-ticks allow multi-line strings.
@Component({
selector: 'inline-template',
template: ` <h2>Inline Template</h2>
<p> Multi-line inline template using back-ticks </p>`
})
export class InlineComponent {}
Angular Templates
• External Templates
– Defined in a separate HTML file
– Referenced with templateUrl.
– Recommended to use if the template contains more than 3 lines.
@Component({
selector: 'external-template',
templateUrl: 'app/templates/external-template.html'
})
export class ExternalComponent {}
Built-in Directives -ngFor
• Part of core directive to build data presentation lists and tables
• Takes an iteration expression
• A loop variable defined using the keyword let
<tr *ngFor="let medicine of medicineList">
<td>{{medicine.medicineName}}</td>
<td>{{medicine.price}}</td>
<td>{{medicine.unit}}</td>
</tr>
<tr *ngFor="let medicine of medicineList let i=index">
<td>{{i+1}}</td>
</tr>
SERVICES
Dependency Injection
• The ability to add functionality to components at runtime.
– Simplify dependency management in software components.
• Done by reducing the amount of information a component needs to
know about its dependencies,
– unit testing can be made easier and code is more likely to be flexible.
Services
• A service is used when a common functionality needs to be
provided to various modules.
– Eg: A database functionality that could be reused among various
modules.
• A separate class which has the injectable decorator
– ng g service my-new-service
• Added to the module to use the service as a provider in the
@Component decorator.
• Services are singleton objects.
• Services are capable of returning the data in the form promises or
observables.
@Injectable
• @Injectable()
– Let know a class can be used with the dependency injector.
– Not strictly required if the class has other Angular decorators on it.
– Best practice is to decorate injectables with @Injectable(), as it is makes
more sense to the reader.
• providedIn: 'root‘
– Indicates that the root injector is responsible for creating an instance
– These are automatically made available to the entire application
– Don't need to be listed in any module.
Model Class
import { Injectable } from '@angular/core';
@Injectable()
export class WeatherData {
minTemp:number;
maxTemp:number;
forecast:string;
constructor(){
this.minTemp=29;
this.maxTemp=30;
this.forecast='thundstrom and rains';
}
getWeatherData(){
return this;
}
}
Service
import { Injectable } from '@angular/core';
import {WeatherData} from "./weather-data";
@Injectable()
export class WeatherService {
data:WeatherData;
constructor(data:WeatherData) {
this.data=data;
}
getWeather(): any {
return this.data.getWeatherData();
}
}
Component
import { Component } from '@angular/core';
import {WeatherService} from "./weather.service";
import {WeatherData} from "./weather-data";
@Component({
providers:[WeatherService,WeatherData]
})
export class AppComponent {
weatherReport:WeatherData;
constructor(private ws :WeatherService){
this.weatherReport=ws.getWeather();
}
*R*eactive E*x*tensions for *J*ava*S*cript
• A library for composing asynchronous and event-based programs
by using observable sequences.
• Observable:
– Invokable collection of future values or events.
– Observable is used to manage async data.
– An Observable can have multiple subscribers and all the subscribers
are notified when the state of the Observable changes.
• Observer:
– Callbacks to listen to values delivered by the Observable.
• Subscription:
– Execution of an Observable
– Used for cancelling the execution by unsubscribing.
• Operators:
– Functions dealing with collections
– map, filter, concat ,etc.
RxJS
var button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked!'));
• Using RxJS
• var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click') .
subscribe(
() => console.log('Clicked!')
);
HttpClient
• Introduced in the Angular 4.3.
• Available in package @angular/common/http
– To replace the older HttpModule.
• The Response returned from the HttpClient is an observable
– Needs to be Subscribed.
– The response can be converted to desired object
Http Client Module
import {HttpClientModule, HttpClient} from '@angular/common/http';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule ,HttpClientModule],
providers: [HttpClient],
bootstrap: [AppComponent]
})
export class AppModule { }
HttpClient
• get() :
– parses the JSON server response into the anonymous Object type.
– Can specify the type of response to make consuming the output easier
and more obvious.
this.http.get<Medicine[]>(this.baseURL)
Get Method
@Injectable( { providedIn: 'root‘ }
)
export class MedicineApiService {
constructor(private http: HttpClient) { }
baseURL = 'http://localhost:3000/medicines';
findAll(): Observable<Medicine[]> {
return this.http.get<Medicine[]>(this.baseURL);
}
}
HttpResponse
• Can provide observe option to specify return data type
– By default, observe is set to body.
– response which returns the full response
– events which returns the full event stream
findAll(): Observable<HttpResponse<Object> {
return this.http.get<Object>(this.baseURL, {observe:
'response'});
}
this.service.findAll().subscribe(resp => {
this.weekEndTripList = <Weekendtrip[]> (resp.body);
console.log(resp.status);
console.log(resp.headers.get('content-type'));
});
Subscribe()
• .subscribe(success, failure, completed);
• Success:
– Whenever observable returns a value.
(response) => { this.repos=response; }
• Failure:
– When observable is failed to generate the expected data or has
encountered some other error.
(error) => {this.errorMessage=error; this.loading=false; },
• Completed:
– When the observables complete its task.
() => {this.loading=false;})
Subscribing
@Component({
selector: 'app-crud',
templateUrl: './crud.component.html',
styleUrls: ['./crud.component.css']
})
export class CrudComponent implements OnInit {
medList: Medicine[]
constructor(private service: MedicineApiService) { }
ngOnInit() {
this.service.findAll()
.subscribe(data => this.medList = data, err => console.log(err));
}
}
Using Promise
findAllWithPromise(): Promise<Medicine[]> {
return this.http.get<Medicine []>(this.baseURL).toPromise();
• Can use in the Component
this.service.findAllWithPromise().then(
res => this.medicineList = res ).catch(
err => console.log(err.error));
Post and Delete Method
add(medicine): Observable<Medicine> {
const headers =
new HttpHeaders().set('content-type', 'application/json');
return this.http.post<Medicine>(this.baseURL, medicine,
{headers});
remove(codeNumber): Observable<Medicine> {
return this.http.delete<Medicine>(this.baseURL + '/' + codeNumber);
}
Progress of Events
• HttpClient can be used to listen for progress events.
• Done by building a request with reportProgress option to true.
• Can subscribe to request object and listen to the different events
• Available Event Types
– Sent
– UploadProgress
– ResponseHeader
– DownloadProgress,
Progress of Events
find(): Observable<Weekendtrip[]> {
const req = new HttpRequest('GET', this.baseURL, {
reportProgress: true
});
this.http.request(req).subscribe(event => {
switch (event.type) {
case HttpEventType.DownloadProgress:
const kbLoaded = Math.round(event.loaded );
console.log('Download in Progress'+ kbLoaded);
break;
}
});
return this.http.get<Weekendtrip[]>(this.baseURL);
}
PROPERTY BINDING
Types of Property Binding
• Element property binding
– works within HTML element
– binds a component property to a DOM property.
<img [src]=" imageUrl ">
• Component property binding
– works within component element
– binds parent component property into child component property.
<app-child [info]=‘data’></app-child>
• Directive property binding
– Works within HTML element with angular directives such
as NgClass and NgStyle.
– Component property or any angular expression is bound to angular
directive.
ELEMENT PROPERTY
BINDING
Element Property Binding
Property Binding
• A One way Binding
• from the component class, to the component’s template.
– sets an element property to a component property value.
– Can be Used for non-string data value.
• Done by wrapping brackets around an element
– <img [src]=" imageUrl ">
– <button [disabled]='isDisabled'>Try Me</button> // in the template
isDisabled: boolean = true; // in the component class
Event Binding
• Event handler are is specified inside the template using ()
– Event handler is then coded in the class to process the event.
• Can take the same property that is on the HTML element wrap it in
parenthesis.
template: `
<h1>My First Angular App</h1>
<img [src]="imageUrl" (click)='myMethod()'> `
imageUrl =‘’assets/images/idly.jpg'
myMethod() {
console.log('Hello);
}
Event Binding
• Can also pass information about the event to the component class:
` <img src=“{{imageUrl}}" (click)='myMethod($event)'> `
myMethod(event:any) {
console.log(event);
}
Two Way Binding
• Combines the input and output binding into a single notation
• Done by using a special directive called ngModel.
• <input [(ngModel)]="name" >
– <input [ngModel]="name" (ngModelChange)="name=$event">
• square braces [..] refers property binding.
• circle braces (..) refers to the event binding.
– Together as [(..)] refers two way binding
• This syntax is called Banana in a Box ([()]).
Two Way Binding- App Module
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,FormsModule
],
providers: [],
bootstrap: [AppComponent,ShowplacesComponent]
})
Two Way Binding
<div> <label>Name:</label>
<input type="text" [(ngModel)]="name">
<h1>Hello {{name}}!</h1> </div>
export class AppModule {
private name:string='World';
}
DIRECTIVES
Directives
• Used to attach behavior to DOM elements.
• Built-in directives to the framework
– NgFor, NgIf, NgModel, NgClass
• There are three kinds of directives:
• Components
– @Component(): Is also a directive with a template.
• Structural Directives
– Can change the DOM layout by adding and removing DOM elements
• Attribute Directives
– doesn’t change the DOM but can change the appearance or behavior of
an element such as NgStyle.
Attribute Directives
• These directives change the appearance or behavior of a
component.
• They work in a way that is component agnostic and not bound to
implementation details.
• Example:
– ngClass and ngStyle work on any component or element.
NgStyle Directive
• To modify a component or element's style attribute.
@Component({
selector: 'style-example',
template: `
<p [ngStyle]="{'background-color':messageStyle}">
`
})
export class StyleExampleComponent {
messageStyle:string='yellow';
}
NgClass Directive
• Directive changes the class attribute that is bound to the component
or element it's attached
• Binding a string
– Can bind a string directly to the attribute.
@Component({
selector: 'class-as-string',
template: `
<p ngClass='centerText'>Page Designed by Ramesh</p>
`,
Binding an Array : A list of applicable class names defined in css
<p [ngClass]="['centerText','highLight']">Page Designed by
Ramesh</p>
Binding an object
• Object can be bound to the directive.
• Each property name of that object to the component if that property
is true.
@Component({
selector: 'class-as-object',
template: `
<p [ngClass]="{ card: true, dark: false, flat: flat }">
<button type="button" (click)="flat=!flat">Toggle Flat</button>
</p>
`,
export class ClassAsObjectComponent {
flat: boolean = true;
• Object's card and flat properties are true
– those classes are applied
– Since dark is false, it's not applied.
Structural Directives
• It’s a "syntactic sugar" for tasks that’s done Internally,
• Its translated into a <ng-template> element
• And then wrapped around the host element Prefixed with an
asterisk.
• ngIf , ngFor , and ngSwitch .
@Component({
selector: 'directive-example',
template: `
<p *structuralDirective="expression">
Under a structural directive.
</p>
`})
Built-in Directives -ngFor
• Part of core directive to build data presentation lists and tables
• Takes an iteration expression
• A loop variable defined using the keyword let
<tr *ngFor="let medicine of medicineList">
<td>{{medicine.medicineName}}</td>
<td>{{medicine.price}}</td>
<td>{{medicine.unit}}</td>
</tr>
<tr *ngFor="let medicine of medicineList let i=index">
<td>{{i+1}}</td>
</tr>
ngFor
• ngFor also provides some other values that can be bound to:
– index - position of the current item in the iterable starting at 0
– first - true if the current item is the first item in the iterable
– last - true if the current item is the last item in the iterable
– even - true if the current index is an even number
– odd - true if the current index is an odd number
*ngFor="let emp of employees;
let even = even; let odd = odd"
[ngClass]="{ odd: odd, even: even }"> {{emp.name}}
Built-in Directives –ngIf
• *ngif="condition“
<div>
<button (click) =“clicked()”>Toggle</button>
<div *ngIf=“show”>
<p> see Image</p>
</div>
</div>
export class AppComponent{
show:boolean =true;
Clicked (){
this.show=!this.show;
}
}
ng-template directive
• Represents an Angular template
• Used for rendering HTML.
– It is never displayed directly.
– It gets loaded as part of parent view content.
– Build in Structural directives use this.
• The content of this tag will contain part of a template
– Which can be composed together with other templates
– Resulting in a final component template.
ngIf
• <h2 *ngIf="condition">Hello {{name}}</h2>
• <button (click)="condition = !condition">Click</button>
• // When the above code is Rendered
<ng-template [ngIf]=“condition">
<h2 >Hello {{name}}</div>
</ng-template>
<!--bindings={
"ng-reflect-ng-if": "true"
}-->
<h2 _ngcontent-c0="">Hello Angular5</h2>
*ngIf and Else
• Components has a defined template in the component class.
– Can display a template if an expression matches some condition.
– <li *ngIf="myArr“>Hello World</li>
• If object myArr is defined, it evaluates to true and displays the
HTML element
• <li *ngIf="myArr == 'something'“>Hello India.</li>
• Can also specify the ! not operator and it won't display the given
HTML element
*ngIf and Else
• Can also declare else as conditions:
template: `
<h1>Greeting !</h1>
<ul> <li *ngIf="myArr; else otherTmpl“>Hello World.</li> </ul>
<ng-template #otherTmpl>Hello India</ng-template> `
• Can also use then inside of expression
template: `
<h1>Greeting</h1>
<div *ngIf="myArr; then tmpl1 else tmpl2"></div>
<ng-template #tmpl1>Here</ng-template>
<ng-template #tmpl2>Not here</ng-template> `,
NESTING COMPONENTS
Nested Component
• The component being used inside another component is known as
the child component
– and the enclosing component is known as the parent
component.
Nested Component -Child
import { Component } from '@angular/core';
@Component({
selector: 'appchild',
template: `<h2>Hi {{greetMessage}}</h2>` })
export class AppChildComponent {
greetMessage: string = "I am Child";
}
Nested Component- Parent
import {Component } from '@angular/core';
import {AppChildComponent} from './appchild.component';
@Component({
selector: 'my-app',
template: `<h1>Hello {{message}}</h1>
<appchild></appchild> `,
})
export class AppComponent {
message : string = "I am Parent";
}
Communication Between Components
• Can share data and information with another component by passing
data or events.
• Components can communicate to each other in different ways:
– Using @Input()
– Using @Output()
– Using Services
– Parent component calling ViewChild
PASSING DATA USING @INPUT
– To pass data into components from template and to dynamically configure
them.
– Supports change tracking.
– Can NOT pass @Input() to a bootstraped component.
• Binds a property within one component (child component) to receive a
value from another component (parent component).
– One way communication from parent to child.
• Component property should be annotated to act as input property.
Child Component
import { Component,Input,Output,EventEmitter, OnInit } from
'@angular/core';
@Component({
selector: 'review-food',
templateUrl:'reviews.component.html',
styleUrls: ['../food-items/food/food.component.css']
})
export class ReviewsComponent {
@Input() reviewedby:string;
details='Reviewed by 200 peoples';
}
Parent Component-One Way Component Property Binding
import { ReviewsComponent } from '../../reviews/reviews.component';
@Component({
Input Property as
selector: 'app-food', defined in
Child
templateUrl: './food.component.html',
styleUrls: ['./food.component.css'],
}) Bound property
in Parent
export class FoodComponent {
reviewer:string = 'Zomoto';
}
• Reviwed by <review-food [reviewedby]='reviewer'></review-food>
• Parent component sets the value of the child component’s
property
Detecting the Input changes
• Child Component can know when the input changes
• Input changes can be detected in the child component by using
– OnChanges LifeCycle Hook
– Using Input Setter
OnChanges
• Import the OnChanges and SimpleChanges
• Whenever parent component changes the value of Input properties
– ngOnChanges() in child component runs automatically.
• Method takes SimpleChanges as an argument
– It gives new and previous value of input values after changes.
• Can find out the details about
– Which input properties have changed
– How they have changed.
Input Change Detection
• Get and Set Method is Decorated with @Input
•
@Input()
set count(count: number) {
this._count = count;
console.log(count);
get count(): number { return this._count; }
•
@output
• One way communication from child to parent component
• Uses events
– binds a property of a component to send data from one component
(child component) to calling component (parent component).
• The child component exposes an EventEmitter property
– It emits events when something happens.
– The parent binds to that event property and reacts to those events.
• The child's EventEmitter property is an output property,
– Its adorned with an @Output decoration
@Output()
sendMsgEvent = new EventEmitter<string>();
sendMsgEvent will be custom event name.
Child Component
import { Component,Input, Output,EventEmitter,OnInit } from '@angular/core';
export class ChildComponent implements OnInit {
Property placeholder to
@Input() childName: string; receive from parent
@Output() result: EventEmitter<String> = new EventEmitter<string>();
constructor() { }
ngOnInit() { }
addData(){
Property To
Parent
this.result.emit(this.childName + 'Added');
}
}
Emit
• emit()
– emit a change to (change) listener in the parent
– Which will invoke the onchange($event) callback
– The data associated with the event will be given via the $event property.
• Child-Component.html
<p>
<button (click)="addData()">Add Medicine</button>
</p>
Parent-component.html
<input type="text" name='user' [(ngModel)]='name'>
<p>
<app-child [childName] ={{name}} (result)="onChange($event)"></app-
child>
{{msg}}
</p>
childName : refers to @Input Property in to Child Component
name : refers to property in the Parent Component
Result : refers to @output Property in Child Component
Parent Compnent
import { Component, OnInit, SimpleChanges } from '@angular/core';
@Component({
})
export class ParentComponent implements OnInit {
msg: string;
name: string;
constructor() { }
ngOnInit() {
}
onChange(val) {
this.msg = val;
}
}
Child to Parent - @ViewChild()
• Used to get the first element or the directive matching the selector from the view
DOM.
– If the view DOM changes, and a new child matches the selector, the property will be
updated.
• @ViewChildren()
• To get the QueryList of elements or directives from the view DOM.
– Any time a child element is added, removed, or moved, the query list will be updated, and
the changes observable of the query list will emit a new value.
Child to Parent Sharing Data
• Child to Parent Sharing Data
– If an instance of the parent component class must read or write child
component values or must call child component methods.
• One component is injected into another
– The parent has access to the child attributes and functions.
– Child won’t be available until after the view has been initialized.
– Need to implement AfterContentInit lifecycle hook
• Can receive the data from the child in this method.
Child Components
export class GuestPhotosComponent implements OnInit {
guestPhoto: string;
constructor() {
this.guestPhoto = 'assets/images/frntView.jpg';
}
}
export class HotelPhotosComponent implements OnInit {
hotelPhoto: string;
constructor() {
this.hotelPhoto = 'assets/images/rearView2.jpg';
}
}
Parent Component
export class GalleryComponent implements OnInit, AfterContentInit
{
hp: string;
gp: string;
@ViewChild(GuestPhotosComponent) guestPhotos:
GuestPhotosComponent;
@ViewChild(HotelPhotosComponent) hotelPhotos:
HotelPhotosComponent;
ngAfterContentInit(): void {
this.gp = this.guestPhotos.guestPhoto;
this.hp = this.hotelPhotos.hotelPhoto;
}
}
Parent Template
<app-guest-photos></app-guest-photos>
<app-hotel-photos></app-hotel-photos>
<img src={{gp}} alt='hello'>
<img src={{hp}} alt='style'>
Passing Data Between Siblings
• Data between siblings, grandchildren passed by a shared service.
• RxJS BehaviorSubject
– Will return the current value on subscription
– A Service is injected into the constructor of one Component
– It then subscribe to an observable
– Set its value equal to a variable.
Behavior Subject
• A special type of observable
– Needs an initial value
– Always return a value on subscription
• On subscription
– Can Return the last value of the subject.
– Can also send values to a subject in addition to subscribing to it.
• Returns an Observable using the asObservable()
BehaviorSubject
let bSubject = new BehaviorSubject("a");
bSubject.next("b");
bSubject.subscribe(value => { console.log(“Got", value);
// Got b,
bSubject.next("c"); // Got c
bSubject.next("d"); // Got d
Service
export class DataService {
private messageSource =
new BehaviorSubject<string>('My Desktop Suggestion');
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message);
}
}
Component - 1
export class ComputerComponent implements OnInit {
suggestion: string;
constructor(private service: DataService) { }
ngOnInit() {
this.service.currentMessage.subscribe(
message => {
console.log('Msg in Computer' + message);
this.suggestion = message;
});
}
Component 2 - Template
{{response}}
<button (click)="newMessage()">suggest </button>
Component -2
export class PrinterComponent implements OnInit {
response: string;
constructor(private service: DataService) { }
ngOnInit() {
this.service.currentMessage.subscribe(message => {
console.log('Msg in Printer' + message);
this.response = message;
});
}
newMessage() {
console.log('Printer is changing message ');
this.service.changeMessage(' Dell Desktop');
}}
Component Interactions
• Parent to Child
– Sharing Data via Input()
• Child to Parent
– Sharing Data via ViewChild()
• Child to Parent
– Sharing Data via Output() and EventEmitter
• Unrelated Components
– Sharing Data with a Service
CUSTOM DIRECTIVES
Custom Directives
• Custom Attributes Directive are created as a class.
ng generate directive [name]
• The class is decorated with the Directive decorator
– specifies a selector which will be looked up in views.
•
• The Class has a constructor which takes two arguments
– ElementRef and Renderer
• <p> <span myUnderline>Hover to underline</span> </p>
Element Reference
• constructor(private el: ElementRef, private renderer: Renderer2) {}
• ElementRef
– A wrapper for the actual DOM element
– Can Uses its property nativeElement to access DOM Elements
el.nativeElement.style.backgroundColor = "gray";
Renderer
• Angular application can be run on environment
– browser, server side via node and on a native mobile device.
• Renderer2
– A platform independent way of setting properties on elements
– Can create element, provide a text and then it can be appended with
any existing element at run time on any event of an element.
– Can add and remove CSS classes, styles, HTML attributes
Renderer
• Methods of Renderer2 service.
• createElement(): Creates element such as <div>, <ul>, <li> etc.
These elements need to be appended with any existing
element.createElement(name: string, namespace?: string|null): any
• createText(): Creates text that needs to be appended with any
existing element.createText(value: string): any
• appendChild(): Appends new element to any existing
element.appendChild(parent: any, newChild: any): void
Simple Directive
<p> appHightlight prefBg="orange"
fntSize="20px">{{eachEmployee.employeeName}}</p>
@Directive({
selector: '[appHightlight]'
})
export class HightlightDirective implements OnInit {
@Input() prefBg: string;
@Input() fntSize: string;
constructor(private element: ElementRef, private renderer: Renderer2) { }
ngOnInit() {
this.renderer.setElementStyle(this.element.nativeElement, 'fontSize', this.fntSize);
this.renderer.setElementStyle(this.element.nativeElement, 'backgroundColor',
this.prefBg);
}}
Directives with Host Listeners
• Specifies which DOM events a directive listens to via a set of
(event) to method key-value pairs:
• event:
– the DOM event that the directive listens to.
• statement:
– the statement to execute when the event occurs.
– If the evaluation of the statement returns false, then preventDefault is
applied on the DOM event.
• To listen to global events, a target must be added to the event
name.
– The target can be window, document or body.
@HostListener
• Used to Listen to the event emitted by host element in a Directive
• Will the Invoke the decorated method when the host element emits
the specified event.
HostListener('click') myClick(){ }
Equivalent to (click)="myClick()"
Directive Example
@HostListener('click') performTask() {
const li = this.renderer.createElement('li');
const text = this.renderer.createText('Click here to add li');
this.renderer.appendChild(li, text);
this.renderer.appendChild(this.elRef.nativeElement, li);
}
Host Listener Directive
export class UnderlineDirective {
constructor(
private renderer: Renderer,
private el: ElementRef
){}
@HostListener('mouseenter') onMouseEnter() {
this.hover(true);
}
@HostListener('mouseleave') onMouseLeave() {
this.hover(false);
}
<h1 appUnderLine>Movie List</h1>
Host Listener Directive
hover(shouldUnderline: boolean){
if(shouldUnderline){
this.renderer.setElementStyle(this.el.nativeElement,
'text-decoration', 'underline');
} else {
this.renderer.setElementStyle(this.el.nativeElement,
'text-decoration', 'none');
}
@HostBinding()
• Used to set properties on the element or component that hosts the
directive,
• Can bind to any class, property or attribute of the host.
– @HostBinding(‘class.active’)
– @HostBinding(‘disabled’)
– @HostBinding(‘attr.role’)
HostBinding('value') myValue;
[value]="myValue”
Directive
@Directive({ selector: '[appHightLight]’})
export class HightLightDirective {
@HostBinding('style.border') border: string;
@HostListener('mouseover') onHover() {
this.border = '5px solid green';
}
@HostListener('mouseout') onLeave() {
this.border = '1px solid red';
}
}
}
<h1 [ngClass]='headCls' appHightLight>Jeevan Blood Bank</h1>
Host Binding – Class
.yellow-style {
background-color: greenyellow;
border: 5px solid black;
display: block;
}
.red-style {
background-color: red;
border: 1px solid black;
color: white;
display: block;
}
Host Binding
@HostBinding('class.yellow-style') yellowStyle = false;
@HostBinding('class.red-style') redStyle = true;
@HostListener('mouseover') onHover() {
this.yellowStyle = true;
this.redStyle = false;
@HostListener('mouseout') onLeave() {
this.yellowStyle = false;
this.redStyle = false;
}
}
Directive and Components
@Components @Directive
• To register the components. • To register the directives.
• To create UI widgets. • To Change or add existing
• To split to application into DOM elements.
smaller parts. • To design a reusable
• Only one component is used components.
per DOM element. • More than one directive are
• template and templateUrl are used per DOM element.
mandatory in the components.
DYNAMIC COMPONENTS
Add Components Dynamically
• Component are not always fixed.
– Applications may need to load new components at runtime.
• Entry Components
– An array containing the components to be added.
– Components are compiled when module is defined.
– For each component listed a ComponentFactory will be created
– ComponentFactory will be stored in the ComponentFactoryResolver.
Add Components Dynamically
• ViewContainerRef
– A Representation of the container to which Views can be attached.
– Injected into a Component’s constructor
– An Element can be obtained via a ViewChild query.
– Passed to Service via a setter method
• Create()
– Creates a new component.
– Returns the Component Reference
• detach(index):
– If the index param is omitted, the last ViewRef is detached.
Host View
• The component’s container contains a Host View
• Generated for each component defined in
bootstrap or entryComponents of a module.
• Each host view is responsible for creating a component view
App.module
@NgModule({
declarations: [
AppComponent,
MessageComponent,
InfoComponent
],
imports: [
BrowserModule
],
providers: [CompAdderService],
bootstrap: [AppComponent],
entryComponents: [MessageComponent, InfoComponent]
})
export class AppModule { }
Component Adder Service
rootViewContainer: ViewContainerRef;
constructor(private factoryResolver: ComponentFactoryResolver ) {
}
setRootViewContainerRef(viewContainerRef) {
this.rootViewContainer = viewContainerRef;
}
addDynamicComponent(compToAdd: any) {
const factory = this.factoryResolver
.resolveComponentFactory(compToAdd);
const component =
factory.create(this.rootViewContainer.parentInjector);
(<ParentComponent>component.instance).message = 'From Service';
this.rootViewContainer.insert(component.hostView);
}
Template and Component
Template:
<button (click)="add()">Add Component</button>
<div #placeHolder>
<h1>Component will be added Here at Run Time</h1>
</div>
Component
@ViewChild('placeHolder', {read: ViewContainerRef}) pholderRef:
ViewContainerRef;
add() {
this.service.setRootViewContainerRef(this.pholderRef)
this.service.addDynamicComponent(ParentComponent);
}
View Encapsulation
• ViewEncapsulation.None
– adds css to the global style
– There is no shadow DOM
– Style is not scoped to component
– Its simple no encapsulation
– Allows styles to cross component boundaries.
ViewEncapsulation
• ViewEncapsulation.Native
– Style is scoped to component
– Styles set on a component do not leak outside of the components
scope.
– Component is isolated from the global styles
– Bootstrap styles are not inherited
– uses the browsers relative shadow DOM which is not supported by all
browsers.
– Angular will create Shadow DOM for the component.
View Encapsulation
• ViewEncapsulation.Emulated
– This is default value for encapsulation.
– Keep styles scoped to the components where they are added
– Any styles we define on a component don’t leak out to the rest of the
application
– Component still inherits global styles like one from twitter bootstrap.
– angular process and renames styles ( no shadow dom)
– Angular will not create Shadow DOM for the component.
– Styles are all added collected in the head of the page when components
are loaded.
PIPES
Pipes
• “Pipes transform displayed values within a template.”
– A pipe takes in data as input and transforms it to a desired output.
• Used in any template.
• Inside the interpolation expression, pipe operator ( | ) is used
• Expression | pipeOperator[:pipeArguments]
Passing arguments
• Can o pass optional arguments to the pipe.
• The arguments are added to the pipe using a colon (:) sign followed
by the value of the argument.
• If there are multiple arguments separate each of them with
the colon (:).
• Date pipe accepts one optional argument called “format”.
{{toDate | date:'medium'}}
Nov 22, 2016, 10:04:10 PM
Chaining pipes
• Can chain pipes together in potentially useful combinations.
• To display the birthday in uppercase, the birthday is chained to
the DatePipe and on to the UpperCasePipe.
• birthday is {{ birthday | date:'fullDate' | uppercase}}
Built In Pipes
– DatePipe,
– UpperCasePipe, LowerCasePipe,
– CurrencyPipe,
– PercentPipe,
– JsonPipe,
• Some of pipes not supported in New versions of angular
– orderBy and filter
• Can by achieved by using “custom pipes”.
Date Pipe
• date_expression | date[:format]
• format indicates which date/time components to include.
– 'medium': equivalent to 'yMMMdjms' (e.g. Sep 3, 2010, 12:05:08 PM for en-
US)
– 'fullDate': equivalent to 'yMMMMEEEEd' (e.g. Friday, September 3,
2010 for en-US)
– 'mediumDate': equivalent to 'yMMMd' (e.g. Sep 3, 2010 for en-US)
– 'mediumTime': equivalent to 'jms' (e.g. 12:05:08 PM for en-US)
– 'shortTime': equivalent to 'jm' (e.g. 12:05 PM for en-US)
Currency Pipe
• currency [ : currencyCode [ : display [ : digitsInfo [ : locale ] ] ] ] }}
• currencyCode is the ISO 4217 currency code,
– USD for the US dollar and EUR for the euro.
• display
– code: Show the code (such as USD).
– symbol(default): Show the symbol (such as $)
– String: Use the given string value instead of a code or a symbol.
• digitInfo
– <p> {{salary | currency:‘USD':'symbol':'4.2-2‘ : ‘fr’}}</p>
Percentage Pipe
• Formats a number as a percentage according to locale rules.
• number_expression | percent[:digitInfo]
• number_expression:
– An angular expression that will give output a number.
• percent :
– A pipe keyword that is used with pipe operator and it converts number
into percent
• digitInfo:
– defines a percentage format.
– {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}
Decimal Pipe
• To format a number as decimal number according to locale rules.
• It uses number keyword with pipe operator.
•
number_expression | number[:digitInfo]
• number_expression:
– An angular expression that will give output a number.
• number :
– A pipe keyword that is used with pipe operator.
• digitInfo :
– Defines number format.
{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}
Pipes Example
<p>The Joining Date is {{ joinDate | date }}</p>
<p>Employee Name is {{name | uppercase}}</p>
<p>Employee Salary is {{salary | currency :'INR':true: '2.2-3'}}</p>
Creating a Custom Pipe
• Ng g p pipeName
• Class is Decorated with “@Pipe”
• Pipes Implement the PipeTransform interface's
– transform method accepts an input value followed by optional
parameters and returns the transformed value.
– Can have one additional argument to the transform method for each
parameter passed to the pipe.
Custom Pipe
@Pipe({ name: 'filter‘ })
@Injectable()
export class FilterPipe implements PipeTransform {
transform(collection: any[], field: string, value: string): any[] {
if (! collection) {
return [];
}
if (!field || !value) {
return collection;
}
if (typeof value === 'string') {
return collection.filter(list =>
list[field].toLowerCase().includes(value.toLowerCase()));
} else {
return collection.filter(item => item[field] === value);
} } }
Sample Data
courseList=[
{"courseName":"java","fees":20000},
{"courseName":"jee","fees":12000},
{"courseName":"python","fees":3000},
{"courseName":"spring","fees":6000},
{"courseName":"hibernate","fees":40000},
{"courseName":"RestWebservice","fees":10000},
]
Template
<input [(ngModel)]="srchCriteria">
<table>
<tr *ngFor="let course of courseList | filter: 'fees' : srchCriteria">
<td>{{course.courseName}} </td>
<td> {{course.fees}} </td>
</tr>
</table>
Two Types Pipes
– Pure by Default
– Impure
• Pure Pipes:-
– Gets executed only when it detects a pure change to the input value.
– A pure change can be primitive or non-primitive.
• Impure Pipes:-
– Get executed during every component change detection cycle.
– Its is called as often as every keystroke or mouse-move.
– Done by setting pure flag to false.
– @Pipe({ name: ‘ImpurePipe', pure: false })
Pipe Definition
@Pipe({
name: 'join',
pure: false
})
export class JoinPipe implements PipeTransform {
transform(array: any, start: any, end: any): any {
console.log('hi i am from transforms');
return array.join(',');
}
}
Component Definition
phones = new Array('iPhone 7', 'samsungJ7', 'Honor 9');
phones2: any[];
data: string;
add(val) {
this.phones2 = new Array();
this.phones2.push(this.data);
this.phones.forEach(element => {
this.phones2.push(element);
});
this.phones = this.phones2;
}
}
Template
<input name="phone" class="form-control" [(ngModel)]='data'>
<button class="btn" (click)="add()">Add</button>
<p>{{phones | join}}</p>
//hi i am from transforms prints for every key stroke
@Pipe({
name: 'join',
pure: true
})
//hi i am from transforms prints for ONLY ONCE WHEN THRE IS A
REAL CHANGE