Angular 2+

Html – JS Dev vs Angular Dev

Earlier we would keep these separate. We will manage the DOM via JS. So on click of a button, we will invoke a particular JS –which might validate form inputs.

Angular works in component based approach, we think in terms of components. So page is divided into components and each component  can have other components inside it. The main component is the root-component.

In angular, we will define form as one component and all the JS is encapsulated inside it. So the components are self-sufficient.

How does angular start?
The index.html might contain certain elements <root-component> etc. The angular read the file main.ts [the first typescript to be called]. In main.ts we bootstrap the root component’s module. The root component’s module declares a root-component. The root-component’s ts file mentions its selector. So angular understands its selector as the element.

Node.js – runtime environment made on Chrome’s V8 JS engine. IT can interpret the code written in angular or other JS frameworks.

Test = node -v

NPM – node package manager manages versions of angular modules . It works on package.json which contains the list of dependencies and libraries needed by the project. Similar to pom.xml maven for java, however npm works on git only.

NPM gets installed with Node installation

After NPM installs we install CLI(ng) from NPM

Npm install @angular/cli    [@group/package

Test =  ng -v

Creation of new project 

ng new <project-name> – this creates new files for the project and dependencies for the needed by it using NPM. It will create bare-bones project with some files.

Angular bootstraps app-root component which needs to be cleaned/ or a new component created in its place.

Creation of new Component

ng generate component <component-name> 

Angular Component contains

  1. Html – view
  2. Css – view
  3. Ts – backing logic
  4. Spec.ts – unit testing

Decorators – Everything that begins with @.  @Component, @NgModule, @Injectable

To declare a .ts  as a component

@Component {

selector :  “app-root” // the tag for this component

templateUrl : “./app.html” // relative path

styleUrls: “./app.css” // relative path

}

When you add a component, it creates 4 files with a folder and changes module.ts file.
In a component – template or templateUrl is mandatory.
selector :  “app-root” – allows to be used <app-root></app-root>
selector :  [app-root] – allows to be used <div app-root></div>
selector :  .app-root – allows to be used <div class=”app-root”></div>


styleUrls can take multiple css files or one can give it inline with styles

DATA Binding

One way binding / a. String Interpolation – {{ }}

ts file -> html

When the value of the variable changes in .ts/data file, it is reflected in view.

One way binding / b. Property Binding – []

ts file -> html

Used to set properties in ts file to control dom elements in view.

<button [disabled]=”isDisabled”>

isDisabled should be a boolean in ts file.

String interpolation to be used when you want to display a text, property binding when you want to control element behavior using ts attribute.

You cannot mix both

One way binding / c. Event binding

The <button click=”funct()” > text </button> behaves as browser click.

The <button (click)=”funct()” > text </button> behaves as angular click and it will find the function in your component.

One can also send funct( $event ).

Two way binding – ngModel

In case we want to update value of variable two ways -i.e data in ts file and UI. It uses the syntax of banana in a box [(ngModel)] = “variableName”

To use this, we need to import FormModule from angular

Aysnc refresh a value 

Use JS API – setInterval (  function(), interval  )

setInterval ( () ->  this.date = new Date().toDateString() , 1000 ) 

This ensures that the value date variable changes every second which is defined in the component.
{{ myFunc(abc, 2) }} – it  can also call functions and display its values.

Directives – Instructions for the DOM

Structural Directives – which have * before them.

*ngIf – if condition for JS

<div *ngIf = “items.length>2”> </div>

*ngFor – to loop over elements/ arrays in JS.
example <p *ngFor=“let item of items” > {{item.element}}  </P>

The star * is only to indicate the angular interpreter that it needs to transform this into a code that uses string interpolation, property binding which angular understands.

The *ngIf block converts to ng-template block with [ngIf] i.e property binding.

Attribute Directives

ngStyle which is a attribute directive used as a property binding. It can help to give a dynamic style to an attribute.

<p [ngStyle]=”backgroundColor: myFunc()”>

ngClass – similar to above but itnstead of adding css styles, it adds css classes dynamically. 

<p [ngClass]=”my-class: myFunc()”>

Intercommunication between components

  1. Parent to child communication

Giving inputs to the components

<app-image src=”./svg/icon.gif” > </app-image>

In the image-component.ts

@Component {
selector :  “app-root” // the tag for this component
templateUrl : “./app.html” // relative path
styleUrls: “./app.css” // relative path
}

export class image {

@Input(‘src’) filePath : string; 

… 

}

‘src’ is an alias – optional.

Input values are populated in ngOnIt() which is called post constructor.. If you try to read the value in constructor, it won’t fetch anything,

The above method simply works for string. In case we want to pass an object to a component?

We will change the syntax to

<app-image [src]=”myObj” > </app-image>

Here, we have used src in square bracket – property binding, this tell angular to take myObj as an object reference and not as a string.

b. Child to Parent Communication

 Giving output / Emitting event from component

in Child component
@Output(‘eventNameAlias’) someEventName: new EventEmitter<MyObj>;

void fun () {

someEventName.emit();

}

In Parent’s html

<child-component (‘eventNameAlias’) = “parentsFunction($event)” >

Attribute vs Structural Directive

Attribute Directive – change or affect the element on which they are user

Structural Directive –  They begin with * for demarcating. Affect the whole DOM.

Making one’s own directive – ng generate directive <name>

a. using just ElementRef approach 

@Directive({

  selector: ‘[appBasicHighlight]’

})

export class BasicHighlightDirective implements OnInit {

  constructor(private elementRef: ElementRef) {

  }

  ngOnInit() {

this.elementRef.nativeElement.style.backgroundColor = ‘green’;

  }

}

It is not considered good to change the elements directly. The DOM should be changed by angular’s API.

Because some of these styles may not be available in web services etc.

b. Using Renderer2 and ElementRef

  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit() {

this.renderer.setStyle(this.elRef.nativeElement, ‘background-color’, ‘blue’);

  }

 We are using Angular API’s to change DOM

c. Using @HostBinding and @HostListener

@HostBinding – simply binds/sets the value to the DOM

@HostListener – reacts to the known events in angular and sets the value in DOM

@HostBinding(‘style.backgroundColor’) backgroundColor: string;

@HostListener(‘mouseenter’) mouseover(eventData: Event) {

   this.backgroundColor = this.highlightColor;

}

backgroundColor, highlightColor can be set using @input / property binding.

View Encapsulation

This is  Angular’s way of emulating the Shadom DOM. In this, a style if applied to a component remains local to it. 

There are three options

@Component({
  selector:
  templateUrl:
  styles: ‘
  encapsulation: ViewEncapsulation.None

})

  • ViewEncapsulation.None – No Shadow DOM at all. Global styles
  • ViewEncapsulation.Emulated – No Shadow DOM but style encapsulation emulation.
  • ViewEncapsulation.Native – Native Shadow DOM with all it’s goodness.

Note – not all browsers support native dom.

Local reference

a. One can refer the Dom element with #<name>

<div class=”col-md-9″>

            <input type=”text” class=”form-control” trim #giftName />

</div>

<div class=”row”>

            <button class=”btn” (click)=”onAddGift(giftName)”>Add Gift</button>

</div>

onAddGift(giftName: HTMLInputElement) {

                           this.userGiftName = giftName.value;

                           }

b. @ViewChild – make an element in ts file of type ElementRef.

<div class=”col-md-9″>

            <input type=”text” class=”form-control” trim #nickName />

</div>

<div class=”row”>

            <button class=”btn” (click)=”onAddGift(nickName)”>Add Gift</button>

</div>

onAddGift(nickName: HTMLInputElement) {

            ..

            this.userNickName = nickName.nativeElement.value;

            .

}

@ViewChild(‘nickName’) nickName : ElementRef;

Content Projection

To write the content between the components.

<myComponent>

<p> hii… this would be ignored</p>

</myComponent>

To make sure it comes change the mycomponents templates with <ng-content></ng-content>

This will place the content between the braces at that location where the tag is present.One cna also enable <ng-content select=”div”> to take up only div elements.

Styling – Local and Global

Component.css can have common style names as of other components. The angular can handle it. So component 1 can have style as “header” with some css properties and component 2 can also have “header” style with other properties. They will not interfere.

In order to have global styles, application specific styles – use styles.css in src folder.

Modules

Are basically a collection of components, services.

ng generate module <name>  -> creates a folder with name and name.module.ts file

To generate components inside this module

ng generate component MyModule/MyApp

This will add this component to the declarations parts of the module file.

To use a module inside another module

  1. Edit AppModule and add import for MyModule

@NgModule {

Imports :[ CommonModule, MyModule]

}

  1. To Use a component declared in MyModule in AppModule

Edit MyModule and add exports for MyAppComponent

@NgModule {

Exports: [MyApp ]

}

Import statement on top of the file is for the typescript compiler. Needed to link types.

Imports in @NgModule decorators is to tell angular which other modules can be used.

Service

ng generate service <MyService>

creates two files

service.ts

service.spec.ts

@Injectable decorator tells it is a service

To use a service in a module

@NgModule {

Providers: [ MyService ]

}

To inject this service into a component, you need to change the constructor of the component

MyComponent {

..

constructor (private serv : MyService ) { }

This will automatically inject MyService in MyComponent.

It is same as

private serv :MyService  ;

constructor ( serv : MyService  ) {

this. serv = serv;

}

Services are loaded in a common pool of injection context. So they are not bound to any particular module or component unlike components which are bound to a module which imports them.

So a service can be declared in any component and it can be used anywhere.

Scope of a Service

Services are injected using a hierarchical injector in angular.

 Example. A has two children

a—-b, a—c

1. If the provider’s array of each of the components will have the service name then all will be using a new instance of service [similar to prototype scope in spring ].

2. If component A has service then all its children will get the same service instance. So if only the root component declares the provider for service, then it will be singleton. [the default in spring]

Injecting Service into Another Service

A service can be injected into another service if and if we use @Injectable() over it.

@injectable() is to be used on the service – which needs other services injected into it.

Angular 6+ Services

Instead of adding a service class to the providers[]  array in AppModule , you can set the following config in @Injectable() :

  • @Injectable({providedIn: ‘root’})
  • export class MyService { … }

This is exactly the same as:

  • export class MyService { … }

and

  • import { MyService } from ‘./path/to/my.service’;
  •  
  • @NgModule({
  •    …
  •    providers: [MyService]
  • })
  • export class MyService { … }

Using Services for InterComponent Communication

Earlier we have seen using parent child, child parent communication. An alternative is service.

Let’s say if a singleton service exists and we emit an event on its property. This can later be subscribed by some other component using the same service.

this.myservice.subscribe ( something to do );

Making a REST call

Import HTTPClientModule in app-root.

User DI to obtain HTTPClient

constructor (private http : HTTPClient ) { }

let response = http.get(“url”);

The response here is not a simple json object. It is an Observable which is an object that handles async calls.

response.subscribe( () -> console.log(“obtained”) )

or

response.subscribe( (json) -> console.log(json) )

So whenever we obtain the response from a web service we execute this function.

Building

Ng build –prod

Routing

Angular works on Single Page Application

Ng new <routing-component-name> –routing

You need to define path , component
a default can also be defined

“*” can be a path for component to open an error page.

<router-outlet></router-outlet> loads the page at that required location.

For children – sub routing 

{path : “settings”, component : ABCComponent 

Children {

path : “profile”, component : ProfileComponent   // setttings/profile

path : “security”, component : SecurityComponent // settings/security

}

<a href=”/path”>  – will refresh the entire page

<a routerLink = “/path” > – behaves as a SPA.

Type of Paths

./ or direct – relative path

/something – absolute path

Styling Routes

In the tag that encloses <a> tag one can use 

<li role=”presentation”

           routerLinkActive=”active”

           [routerLinkActiveOptions]=”{exact: true}”>

         <a routerLink=”/”>Home</a>

       </li>

First option routerLinkActive sets the active style class and the other is used to set it to be true for exact match for absolute path. Otherwise all links that start with “/” will be made active.

Navigating Programmatically

  1. Absolute Path
    Inject Router in constructor

onLoadServer() {

   this.router.navigate([‘/servers’]);

 }

  1. Relative Path – it needs the active routes information
    Inject Router and ActivatedRoute in constructor

this.router.navigate([‘servers’] , {relativeTo: this.activatedRoute} );

 Passing Params Dynamically

Passing params
{ path: ‘servers/:id’, component: ServerComponent) 

Retrieving Params
Inject ActivatedRoute
this.activatedroute.snapshot.params[‘id’]

Retrieving Params Reactively
If one of the same components tries to click on the link that tries to open the same component again – angular wouldn’t reload the component.
However, in order to reload/re-instantiate the component one can subscribe to the changes in the params in ngOnInit().

this.paramsSubscription = this.route.params

     .subscribe(  (params: Params) => {

         this.user.id = params[‘id’];       }

However, also unsubscribe the event on ngOnDestroy()

Passing Query Params and Fragments

  1. using <a> tag
    <a  [routerLink]=”[‘/servers’, server.id]”

       [queryParams]=”{allowEdit: server.id === 3 ? ‘1’ : ‘0’}”

       fragment=”loading”>

       {{ server.name }}

     </a> 

b.  using function
this.router.navigate([‘/servers’, id, ‘edit’], {queryParams: {allowEdit: ‘1’}, fragment: ‘loading’});

/server/1/edit?allowEdit=1#loading

Retrieving Query Params and Fragment
Inject ActivatedRoute
this.activatedroute.snapshot.queryparams[‘allowEdit’]

Retrieving Params Reactively
Similar to params , one can subscribe to the changes in the query params in ngOnIt().

Note : the params retrieved from url are in string. So if you consider passing them make sure to typecast them.

Preserving or merging query params on click of new link

queryParamsHandling: “preserve” – lets them remain same

queryParamsHandling: “merge”- merges any new params in the link

Child Routes

In case there are multiple components inside a component which are its children. So one can give routing in this manner.

{ path: “” , component : HeadComponent, children : {

{ path : “” , component : ChildComponent }

} } Note : the path here needs to be relative one as it is a child’s path

Add <router-outlet> to HeadComponent instead of ChildComponent’s selector tag. This will load only child of this component.

Redirecting to non found page

{ path “not-found” , redirectTo : PageNotFoundComponent },

{ path “**” , redirectTo :” /not-found” }

** is whatever path angular doesnt understand.

redirectTo – changes the url to point to this

pathMatch: ‘full’

 Angular uses prefix matching by default. this can cause issues because ” will match every URL.

 Router Guards

 1. CanActivate Guard – To block access to certain URL’s which do not have the permission to access the resource.

Steps

a. Implement CanActivate in a class(this is called a Guard class) and implement the method canActivate() which returns a true or false.

b. Invoke a service inside this method to decide on the access.

c. Add this class to providers [because it acts a service]

d. In const of routes, add canActivate property and name the Guard class in array. There can be many Guards

path: ‘artist/:artistId’,  component: ArtistComponent, canActivate: [AlwaysAuthGuard]

 2. CanActivateChild Guard

For child routes – same steps only a different interface CanActivateChild needs to be implemented and different property

path: ‘artist/:artistId’,  component: ArtistComponent, canActivateChild: [AlwaysAuthChildGuard]

3. CanDeactivate Guard – suppose a user is changing form data and before saving, user tries to navigate away. In this scenario we can use CanDeactivate guard which will deactivate the route and open a Dialog Box to take user confirmation. This Guard is usally only a single one for application.

It works on Command Design pattern

a. Create a new interface which has only a  canDeactivate() method that returns either an observable, promise or boolean.

b. Make a new Guard class which extends CanDeactivate<T>. Above new interface will act as a generic type to CanDeactivate<your new Interface type here>

c. In the class we will call the component’s canDeactivate method.

d. Add this class to providers [because it acts a service]

e. Any class which needs to be Guarded needs to implement CanDeactivate<Component>.

f. In const of routes, add canActivate property and name the Guard class in array. There can be many Guards

path: ‘artist/:artistId’,  component: ArtistComponent, canDeactivate: [DeActivateGuard]

Passing data to a route can be done statically via (data : “string” in routes) and dynamically by a resolver ( intermediate code to be executed when a link has been clicked and before a component is loaded)

Observables

Observables are data sources – could be events, Http requests, Triggers in code (All of which happen at a random time so its async in nature).

These need to be handled by angular. An Observer handles them. An observer has three parts – normal execution, error situation , completion of execution.

So when you subscribe to a variable – > the variable is itself an Observable and everything inside subscribe(  observer: Observer  ) is an observer.

myobserver : Subscription = abc.subscribe()

onDestroy() {

             this.myobserver.unsubscribe();

}

Observables need to be unsubscribed if they are created by the user.. Angular ones are automatically taken care of.

We pass values to an observer using observer.next( //some value here );

Subjects

They act as both observer and observable. They can be effective for communication between components. They can replace EventEmitter

Example

A simple class lets say MyService has an object on subject.

Two components A and B inject this service.

A can pass values to the subject.

B can subscribe and read those values.

Pipe

Transforms the output without changing the property

{{name | uppercase }}

You can chain pipes.

 You can make a custom pipe too by implementing PipeFilter interface or using ng generate pipe <name> command. Each pipe is initially impure (won’t react on changes if the value has changed). It can be made pure with a performance hit.

 You can have async pipes

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *