angular

https://angular.io/guide/lazy-loading-ngmodules

Angular is a framework for building client applications in HTML, CSS and Javascript/TypeScript, it gives the application a clean and loosely coupled structure i.e easy to understand and easy to maintain. It also brings in a lot of utility code that we can reuse in various applications, and applications built using Angular are more testable, so you can easily write various automated test cases to test various parts of your application. Using Angular makes life a lot easier.

npm install -g @angular/cli@latest
ng new my-first-app
ng serve -o

Angular CLI uses a tool called webpack, webpack is a build automation tool, it gets all our scrips/stylesheets and combinds them put them in a bundle and minifies that bundle for optimization.

-polyfills.bundle.js # which includes all the scripts that required for running angular which are not available for the browser by default.
-main.bundle.js # which includes all the source code of our application
-styles.bundle.js # which includes all our stylesheets
-vendor.bundle.js # which includes all the third party libraries
-inline.bundle.js # This is a webpack loader. A tiny file with Webpack utilities that are needed to load the other files.

whenever the source files like stylesheets/typescript files/html files updated, webpack will automatically recompiles the application and refreshes the bundles, and without even refreshing the browser, all the new changes will be reflected in the browser, so, this is a feature of webpack called "Hot Module Replacement/Reloading (HMR)"

ng install --save bootstrap@3
#update angular.json configuration file by adding bootstrap css in styles array
## make sure you restart the server for to make the changes updated in the app

ng g c compName  ## command to create a new component through CLI
## ng g c recipes/recipe-list --spec false (here RecipeList Component will be created without spec doc under the recipes folder.
ng g d better-highlight ## generate directive
ng g p currency ## generate a custom pipe
ng g s services/backendApi ## generate services
ng generate module app-routing --flat --module=app
--flat puts the file in src/app instead of its own folder.
--module=app tells the CLI to register it in the imports array of the AppModule
ng generate class Dummy [options] ## generates class Dummy

--------------------------------------------------------------------------------------------------------------
@Input() imgUrl = 'abc.com/2323';
@Output() emitImgUrl = new EventEmitter<string>(); 

<app-dalcha [imgUrl]='imgUrl' (imgUrlEmit)="updateMe($event)">This is some content projection</app-dalcha>
--------------------------------------------------------------------------------------------------------------
json to typescript interface
 
https://quicktype.io/typescript
--------------------------------------------------------------------------------------------------------------


##Decoratives##
@Component
@NgModule
@Directive

A decorator is a function that is invoked with a prefixed “@” symbol and is immediately followed by a class, parameter, method, or property.
A decorator returns the same thing which was given as an input but in an augmented form.

There are 4 different types of decorators:

Class decorators
Property decorators
Method decorators
Parameter decorators

##Modules##
A Module is a container for a group of related components. Every Angular application should have one module called App Module.

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    UserComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [UsersService],
  bootstrap: [AppComponent]
})
export class AppModule { }


##when working with ngModel you should load FormsModule in app-module from @angular/forms, as we are binding with form input elements.

##components##
A component encapsulates data, html markup and some logic for a view.
Note: A component should not include any logic other than the presentation logic.

#steps
1) Create a Component
2) Register it in a Module delcarations array
3) Add an element in an HTML markup

selectors can be 3 types as an element name or property or a class name
@Component({
  selector: 'app-root', (or) '[app-root]' (or) '.appRoot' [(or) '#appRoot']
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit, OnDestroy {

##Data Binding##
String Interpolation ## {{ data }} // whenever just want to display values in html tags use string interpolation
Poperty Binding ## [property] = "data" // if you are setting up the value for the element Attribute use property binding
Event Binding ## (event) = "expression"
## $event is a reserved keyword
## (<HTMLInputElement>event.target).value here we are marking the event type is as a input type event
Two way binding ## [(ngModel)] = "data"
One way binding ## [ngModel] = "data"

##Directives##


Directives are the instructions in the dom, there are builtin directives available in Angular and we can create our own custom directives
#two types of directives
1) "Attribute Directives" (sits on element & only change the element that are added to) and
ex: ngStyle, ngClass
2) "Structural Directives" (change the structure of the dom, affects a whole area in the DOM like el gets added/removed)
ex: *ngIf, ngSwitch -> *ngSwithchCase

*ngIf (*indicates structural directive that changes dom)
<p *ngIf="serverCreated; then serverAvailable else noServer" ></p>
<ng-template #serverAvailable>Server was created, server name is: {{serverName}}</ng-template>
<ng-template #noServer>No Server created</ng-template>## here noServer is a LOCAL REFERENCE

<div [ngSwitch]="viewMode">
<div *ngSwithchCase="'map'">Map View Content</div>
<div *ngSwithchCase="'list'">List View Content</div>
<div *ngSwithchDefault>Otherwise</div>
</div>

[hidden] ## <div [hidden]="courses.length == 0">
[ngStyle] ## [ngStyle]="{backgroundColor : getColor()}"
[ngClass] ## [ngClass]="{'online': serverStatus === 'online', 'offline': serverStatus !== 'online'}"

ng for loop
------------
<div class="Table">
<ng-container *ngFor="let dataList of defaultValuesDataSource; index as i">
  <div class="Row" *ngFor="let dataItem of dataList; index as j">
  <div class="Cell">{{ dataItem.key }}</div>
  <div class="Cell">{{ dataItem.name }}</div>
  <div class="Cell">{{ dataItem.value }}</div>
  <div class="Cell">{{ dataItem.type }}</div>
  </div>
</ng-container>
</div>


*ngFor ## <app-server *ngFor="let server of servers; index as i; trackBy: trackServer"></app-server> ##when you are dealing with large data sets with complex markup and you do notice performance problem in the page, you can try trackby option to improve the performance of the page
app.component.ts
----------------
trackServer(index, server){
return server ? server.id: undefined;
}

##Safe Traversal Operator - undefined issue
task= {
title: 'Review',
assignee: null ## here assignee is null
}

<div> {{ task.assignee.name }} </div> ##it will give error as assignee is null, generally we can fix this is *ngIf, but with safe traversal operator we can easily fix this like below;

<div> {{ task.assignee?.name }} </div>

##view encapsulation in @Component directive## related to the component styling
encapsulation: ViewEncapsulation.Native (None, Emulated)
Emulated is default # Angular differentiate all the components by adding unique attributes to every component elements
None # you can disable this custom styling and the parent styles will be applied to the component
Native # uses shadow dom technology, this will give same result as emulated but only browsers which supported shadow dom

ShadowDOM -- allows us to apply scoped styles to elements without bleeding out to the outer world.

#### component communication between elements ####
- 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
//service
private messageSource = new BehaviorSubject('default message');
currentMessage = this.messageSource.asObservable();
        changeMessage(message: string) {
this.messageSource.next(message)
}
// parent component
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
  newMessage() {
this.data.changeMessage("Hello from Sibling")
  }

##Passing data from the Parent Elements to Child Elements##
<child-el [serverData]="serverData"></child-el>
#input decorator - enables to capture data from parent element to child element as a attribute property value
#input property declaration ex:
@Input() serverData: {serverName: string, serverContent: string, id: number} ## here serverData can be binded from parent property
##binding input with alias (alias will make the Component API contract intact, even if you change the input parameter name the parent element need not to change)
@Input(srvDataInfo) serverData: {serverName: string, serverContent: string, id: number} ## here the parent element should pass data to alias "srvDataInfo" not to serverData

Note: you can also pass an array of input elements in the Component Decorator instead of declaring the @Input() as shown below;
@Component({
...
input: ['serverData'] // this approach is not recommended, if we rename this input field in the future and forget to update this array application will fail.
}

##Passing data to the Parent Elements from the Child Elements##
From child element using "Event Emitters" (custom events) we can notify and send the required data to the parent element
#parent html child element declaration ex:
<child-el (serverAdded)="onServerAdded($event)"></child-el>

#adding output event emitter in child element ex:
import { Component, Input, EventEmitter, Output } from '@angular/core';
@Output('serverAdded') serverCreated = new EventEmitter<{serverName: string, serverContent: string}>(); // passing properties to the constructor\
//in the child element whenever required call emit()
#emit the event in your method
someFunction() {
this.serverCreated.emit({serverName: this.newServerName; serverContent: this.newServerContent});
}
#Parent element method will be called whenever the child element emits the event.
onServerAdded() // will be called in the parent element.

#Calling child method from the parent#
@Component({
  selector: 'child-cmp',
  template: '<p>child</p>'
})
class ChildCmp {
  doSomething() {}
}
@Component({
  selector: 'some-cmp',
  template: '<child-cmp #child></child-cmp>',
  directives: [ChildCmp]
})
class SomeCmp {
  @ViewChild('child') child:ChildCmp;
  ngAfterViewInit() {
    // child is set
    this.child.doSomething();
  }
}


##local references## or local variables
When two way binding is not required we can use local references (instead of ngModel) and pass data to the component.
local references a very nice feature to get access to some elements in your template and then use that directly in the template or you can pass it to the component methods. local references can be placed on any html element anything you see in the template, with hash and a name of our choice ex:
<input type="text" #serverNameInput>
<button (click)="onAddServer(serverNameInput)">Add Server</button>

##accessing local references from template to the type script code##
#create viewChild property and pass the local reference name in the Component
@viewChild('serverNameInput') serverNameInput: ElementRef; //ElementRef is a service defined in Angular that gives us access to the dom object
#now you can access the local reference value as
serverName = this.serverNameInput.nativeElement.value;

Note: you should not change the element from the typescript even you have access to it, it is not recommended.
Note: you should use the Renderer2 for any DOM element manipulations

## Rendering dynamic html content from parent element to child element ##
this can be possible using <ng-content> hook.
Whatever the content we have in between child element tag, that can be rendered in the child template by using <ng-content> hook
#in parent template
<child-el [serverData]="serverData">
<p class="heading">{{serverData.name}}</p> #added a class here
<p card-body>{{serverData.content}}</p> #added a attribute here
<pcard-type="body">{{serverData.content}}</p> #attribute with a value
<card-footer>this is a footer</card-footer> # html element with a value
<ng-container class=".header">{{serverData.name}}</ng-container> # if you don't want to render any html elements around the content use ng-container
</child-el>
#in child template use the below code to render the content.
# you can select by Attribute, HTML tag, or CSS class, it is recommended to use an attribute because it's readable. An HTML tag/element is also readable but you need to add schemas: [ NO_ERRORS_SCHEMA ] in @ngModule metadata.
<ng-content select=".heading"></ng-content> #class selector, this will replace with the element that has class heading, this case <p> tag will be shown
<ng-content select="[card-body]"></ng-content> #attribute selector
<ng-content select="[card-body=body]"></ng-content>  #attribute with a value
<ng-content select="card-footer"></ng-content> #element selector
This is a nice feature especially if you think about building re-usable widgets like a tab widget where each tab have a content which probably comes from some other source and which you don't want to pass throw property binding.
#use ng-container if you don't want to render any html elements around the content.
<child-el [serverData]="serverData">
<ng-container class=".header">{{serverData.name}}</ng-container>
</child-el>

## accessing ng-content data using Local Reference ##
You can't access local reference that is placed on the parent element where ng-content is projected using @viewChild, as it is not part of the child template.
We have @contentChild property to access the local reference that is placed in parent element.
Just like viewChild, with the help of contentChild we can access the local Reference that is placed in parent template.

@contentChild('contentParagraph') paragraph: ElementRef

<child-el [serverData]="serverData">
<p #content-paragraph>{{serverData.name}}</p>
<p>{{serverData.content}}</p>
</child-el>

console.log('text content of paragraph' + this.paragraph.nativeElement.textContent);



##Life Cycle Hooks##


Lifecycle of a component includes :
-------------------------------------
- Creating a component
- Rendering a component
- Creating and rendering its child components
- Checking data-bound properties
- Destroying and removing it from DOM

What is a lifecycle hook?
---------------------------
The number of methods called in a sequence to execute a component at specific moments is known as lifecycle hook.

The first step of the lifecycle is to create a component by calling its constructor.
Once the component is created, the lifecycle hook methods are followed in the following sequence:

ngOnChanges( ) — It is called before ngOnInit( ) and whenever one or more data-bound input properties change. It detects simple changes in the property values.

ngOnInit( ) — It initializes the directive/component after Angular displays the data-bound properties and is called once after ngOnChanges( ).

ngDoCheck( ) — Changes that are not detected by Angular itself are detected and resolved by it. It is called every time a change is detected and immediately after ngOnChanges() and ngOnInit( ).

ngAfterContentInit( ) — Respond after Angular projects external content into the component’s view / the view that a directive is in. It is called once after the first ngDoCheck( ).

ngAfterContentChecked( ) — After the content is projected in the component, this method responds. It is called after ngAfterContentInit( ) and every ngDoCheck( ).

ngAfterViewInit( ) — It responds after Angular initializes the component’s views and child views / the view that a directive is in. It is called once after the first ngAfterContentChecked( ).

ngAfterViewChecked( ) — Respond after Angular checks the component’s views and child views / the view that a directive is in.Called after the ngAfterViewInit( ) and every subsequent ngAfterContentChecked( ).

ngOnDestroy( ) — Cleanup just before Angular destroys the directive/component. Unsubscribe Observables and detach event handlers to avoid memory leaks.Called just before Angular destroys the directive/component.

----------------------------

https://angular.io/guide/lifecycle-hooks

Once a new component is instantiated angular goes for a couple of different phases in this creation process and it will actually give us a chance to hook into these phases and execute some code. We can hook into these phases by implementing some methods angular will call if they are present.

#ngOnChanges(changes: SimpleChanges)|| will take one argument which is a type of SimpleChanges object
The first hook we can hook into is ngOnChanges()
and this may actually be executed multiple times, it's executed right at the start when a new component is created but thereafter
it's also always called whenever one of our data bound input properties i.e properties decorated with @Input() changes.
So whenever these properties received new values ngOnChanges will be called.

Respond when Angular (re)sets data-bound input properties.
The method receives a SimpleChanges object of current and previous property values that are updated.
Called before ngOnInit() and whenever one or more data-bound input properties change.

#ngOnInit()
Initialize the directive/component after Angular first displays the data-bound properties and sets the directive/component's input properties.
Called once, after the first ngOnChanges().

This method gets executed once the component has been initialized.
This does not mean that we can see it. It has not been added to the DOM yet so to say it has not been displayed yet but Angular finished a basic
initialization. Our properties can now be accessed and initialized for example. The constructor will run first then ngOnInit.

#ngDoCheck()
Detect and act upon changes that Angular can't or won't detect on its own.
Called during every change detection run, immediately after ngOnChanges() and ngOnInit().

ngDoCheck will also run multiple times.
Actually this method will be executed a lot because this will run whenever change detection runs.
Now change detection simply used a system by which angular determines whether something changed on the template of a component or inside of a component.
So whether it needs to change something in the template or some property value changed from 1 to 2 let's say.
or if you clicked some button which doesn't change anything, but still it's an event and on events Angular has to check if something changed or not.
So it has to check on certain triggering events like you clicked somewhere or a timer fired or an observable was resolved.

#ngAfterContentInit()
Respond after Angular projects external content into the component's view / the view that a directive is in.

This is called whenever the content which is projected via <ng-content> has been initialized.
So not the view of the component itself but instead you could say the view of the parent tell what component especially the part which will get added to our component through <ng-content>
Called once after the first ngDoCheck().

#ngAfterContentChecked()
Respond after Angular checks the content projected into the directive/component.
Called after the ngAfterContentInit() and every subsequent ngDoCheck().

#ngAfterViewInit()
Called after Angular initializes the component's views and child views / the view that a directive is in.
Called once after the first ngAfterContentChecked().

#ngAfterViewChecked()
Called after Angular checks the component's views and child views / the view that a directive is in.
Called after the ngAfterViewInit and every subsequent ngAfterContentChecked().

#ngOnDestroy()
Cleanup just before Angular destroys the directive/component. Unsubscribe Observables and detach event handlers to avoid memory leaks.


##host listeners in directives
Using host listeners we can react to any dom events like mouseenter, mouseleave etc.
@HostListener('focus') onFocus(eventData: Event) {
this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue', false, false);
}
@HostListener('blur') onBlur() {
console.log('on Blur');
}

##host binding in directives
using @HostBinding you can point to any property of the element the directive is sitting on
@HostBinding('style.backgroundColor') backgroundColor: string = 'transparent';
this.backgroundColor = green; //now here we are changing the background style of the element without using ElmentRef

##custom structural directives##
<input type="text" inputFormat /> # here input-format is the custom directive
<input type="text" inputFormat [format] = "'lowercase'"/> # here we are passing input data to the custom directive
# in the custom directive you need to have a Input parameter like below
@Input('format') format;
<input type="text" [inputFormat] = "'lowercase'"/> # if you have only one input property you can have the selector of the directive as an alias of that property
@Input('inputFormat') format;

##Template Ref##
TemplateRef to get the reference of ng-template
ViewContainerRef to get the reference of the view Container

##Services##
Services in Angular are plain Type Script classes, which needs to be registered as providers in the app module or in the component
we can actually share data between multiple components using services
we can write or handle custom logic and things that are reusable into the services
So, when the application grows it is a good practice to move view-independent logic from the component into a service, so it can be reused by other parts of the application as well.
services are Sigletons that's why once you create one of these, anything can share it and they provide a great way to encapsulate reusable functionality

##Dependency Injector##
A dependency is something a class of ours will dependend on.
For example we have a component that depends on some service, lets call it as a logging service, so to call a method in that service we need to create an instance of the service, here the dependency injector simply injects this dependency instance of this logging service into our component automatically.
So you need not to create a instance manually, all we need to do is we need inform angular that we require such an instance of the service
by adding a private parameter of the required service type in the constructor and add service in providers array in the Component decorator object.

DRY - don't repeat yourself.

##injecting a service into service##
@Injectable() - when you add injectable directive to the typescript class Angular recognizes this class as it is injectable or something can be injected there to be.

(Note: When your Service is sharing among the components make sure you add service provider only in the root component, and remove it from the child components.
So that, all the components will share same Service provider object otherwise the app won't work properly.)

## Routing ##
Routing configuration should be done in the app module,
1) you should import Routes and add array of objects with path and component parameters;
const appRoutes: Routes = [{path: '', componet: HomeComponent}, {path: 'users/:id/:name', component: UsersComponent}]
2) import RouterModule and add RouterModule in Import array of app module.
imports: [ .... , RouterModule.forRoot(appRoutes)]
3) add <router-outlet></router-outlet> to load the page content
4) routerLink="/" or [routerLink]="['/users','556']" in the menu link
5) routerLinkActive = "active" [routerLinkActiveOptions]="{exact: true}" // this will add active property if we are on the active page.
6) this.router.navigate(['/users']) // programatically navigate to a page
7) ActivatedRoute this object will contain all the information about the currently loaded route, we can access the parameters
id: this.route.snapshot.params['id'] // we are fetching the id parameter from the route.
8) query parameter - <a [routerLink]="['/users', 4, 'edit']" [queryParams]="{allowEdit: '1'}" fragment="loading" href="#"><a/>
ex: localhost:4200/users/4/edit?allowEdit=1#loading
this.router.navigate(['/users', id, 'edit'], {queryParams: {allowEdit: '1'}, fragment: 'loading'});
9) Nested routes
[
{path: 'users/:id/:name', component: UsersComponent,
children: [
{path: ':id', component: UsersComponent},
{path: ':id/:name', component: UsersComponent},
]
}
]
10) redirecting - 404 handling
{path: 'not-found', component: PageNotFoundComponent},
{path: '**', redirectTo: '/not-found'} // this wildcard path should be the last in the list
11) CanActivate guard: for guarding the route for checking the authentication
{path: 'users/:id/:name', canActivate: [AuthGuard], component: 'UsersComponent'} // all the child route will be guarded
CanACtivateChild to guard all the child routes
{path: 'users/:id/:name', canActivateChild: [AuthGuard], component: 'UsersComponent'}
CanDeactivateGuard - to alert the user to redirect if there is any changes to discard
12) userHash ex: localhost:4200/#/users
RouterModule.forRoot(appRoutes, {userHash: true})

## Subject ##
Subject is similar to Observeable, but a subject is Observable and observer at the same time.
userService = new Subject();
this.userService.userActivated.next(this.id);
this.userService.userActivated.subscribe();

instead of EventEmitter better to use Subject (in the place of emit you call next)
Note: when you are using your custom Observables/Subject make sure you unsubscribe to prevent memory leaks

## Forms ## 2 kinds of approach angular handles the forms
1)Template driven Approach ## you setup the form and angular will automatically infer the structure of your form and the inputs in the form
2)Reactive Approach ## type script will create form programatically

diff between Reactive & Template-driven

Reactive Template-driven
----------- -----------------
- More control over validation logic - Good for simple forms
- Good for complex forms - Simple Validation
- Unit testable - Easier to create
- Less code

#Tempalte Driven Forms#
you should import FormsModule  in your module

<form (ngSubmit)="onSubmit(f)" #f="ngForm">
<input name="username" ngmodel>
{{ f.value | json }} #you can see all the values of the forms here
//in the controller
onSubmit(form: ngForm) { console.log(form) } // here in form under "value" object you will have all the ngmodel values of the form

as we have Local Reference of the form, we can use it by declaring the @ViewChild():
@ViewChild('f') signupForm: NgForm
onSubmit() { console.log(this.signupForm) }

ng-invalid ng-touched

//displaying inline error messages
<input type="email" name="email" required email #email="ngModel">
<span class="help-block" *ngIf="!email.valid && email.touched">Please enter a valid email!</span>

ngModelGroup ## to group the form data and validate the structure of the group
<div ngModelGroup="userData" #userData="ngModelGroup">... form inputs ...</div>
in NgForm under value you can see now userData
using localreference you can get the javascript object with that you can validate the group of data
<p *ngIf="!userData.valid && userData.touched">User Data is invalid!</span>

dropdown # when you want send the value and the name of the selected option use [ngValue]="country" now ngValue will contain the key and the value
if you want to set a complex value like an object to the value property use [ngValue]


******skipped ******* 187-191

##Reactive Driven Forms##

#more control over form structure and behaviour
#if you want to build dynamic forms where input fields are rendered based on some datastructure that you get from a server then use the reactive forms
#reactive forms are easier to unit test

you should import ReactiveFormsModule in your module
in the template import FormGroup,FormControl,Validators from @angular/forms

signupForm: FormGroup;
ngOnInit() {
this.signupForm = new FormGroup({
'username': new FormControl(null, Validators.required),
'email': new FormControl(null, [Validators.required, Validators.email]),
'gender': new FormControl('male')
});
}

<form [formGoup]="signupform"> ##here we are instructing that this form should be connected with signupForm Formgroup that we have created in our controller
<input type="text" id="username" formControlName="username"> ## this input should be connected with formcontrol that we have created in our controller
<span *ngIf="!signupForm.get('username').valid && signupForm.get('username').touched">show error msg</span>
</form>

##Pipes## are a feature built into Angular to which basically allows you to transform output in your template.
- Tranforms the output, we have built in pipes and we can build a custome pipe
<p>{{username | uppercase}}</p>
<p>{{rating | number:'2.2-2'}}</p> # 4.9745 -> 04.97
<p>{{rating | number:'1.1-1'}}</p> # 4.9745 -> 5.0
<p>{{ server.started | date.'fullDate' | uppercase}}<p> # pipe chaining
uppercase
date:'fullDate' # passing parameter to date pipe



##Custom pipes##
@Pipe({name: 'shorten', pure: false}) ## pure false will be used to recalculate the pipe on the dynamically added data (note: performance issue with it)
implement PipeTransform interface and add transform() method and return the output
and add the custom pipe in the ngmodule declaration array

@Pipe({name: 'shorten'})
export class ShortenPipe implements PipeTransform {
transform(value:any, limit: number) {
if(value.length > limit) {
return value.substr(0, limit) + '...';
}
return value;
}
}

Add the pipe in the modules delcarations array

#async pipe#
{{appStatus | async}} # here appStatus is a promise object and it will be resolved in 2 secs, if you don't add 'async' it will be displayed as "Object Object" and when you add async it will wait till the promise is resolve or reject and display the returned value.
it will also works with the observables

##HttpClient## module gives concept of intercepters (otherwise you can use the old HttpModule, which is deprecated in 4x)
import HttpClient from @angular/common/http in app module.

You can send configuration parameters in the sencond argument of Get, where you can pass the query parameters
#Requesting Events
we can listen to the events, in cases where you want to do something once the request was sent and you're still waiting for a response.
so now we have a way of getting in this process and actually doing something. Was the request and response are on their way.

instead of this.httpClient.put() or this.httpClient.get(), we can use new HttpRequest()

#Progress Event# uploading downloading files
in the configuration params you can add reportProgress: true which will return {type:1, loaded: 500, total: 500} you can have %of pogress logic loaded/total

#Interceptor# HttpInterceptor
before on every http request if we want call a method where we can send additional headers like authentication details or logging the request data we can create a interceptor class and register it in the module providers array.
# we can modify request.


##NgRx##
state management solution for angular, if you dealing with data that is medium to large size angular application, and you are passing it in different components it make sence to use something like NgRx, it makes life easier especially when you are debugging and trying to test your application.
NgRx is a third party library built on top of RxJs library


## using material design
ng new material-demo
cd material-demo
npm i --save @angular/cdk @angular/material @angular/animations hammerjs
@import "~@angular/material/prebuilt-themes/indigo-pink.css";

create a css file (theme.scss) and add it in to the styles array of angular.json
"styles": [
"src/styles.css",
"src/theme.scss"
],

now import the material theme into our new theme.scss file, and configure the primary, accent and warn styles.
theme.scss
-------------
@import "~@angular/material/_theming";

@include mat-core();

$app-primary: mat-palette($mat-blue, 300);
$app-accent: mat-palette($mat-blue, 900);
$app-warn: mat-palette($mat-red);

$app-theme: mat-light-theme($app-primary, $app-accent, $app-warn);

@include angular-material-theme($app-theme);

##Unit Tests##

Karma - test runner
Jasmine - testing framework, that has bunch of functions that we can use for testing.

ng test --> will start Karma test runner

#test case file should be xxxx.spec.ts --> Karma will run all the spec files

we can write test specs for components, directives, pipes etc., in spec file

#describe() // is a suite (group of related tests)
#it() // is a spec (test)

##Arrange - Act - Assert (AAA's in test case)

// set up functions
#beforeEach() // executes before each test case
#beforeAll() // executed only once before all the test cases

// tear down functions
#afterEach() // executes after each test case
#afterAll() // executed only once after all the test cases

#TestBed# is a main angular testing utility object. this allows configuring the module for testing.
#isolated and non isolated tests#

user.component.spec.ts
===========================
/* tslint:disable:no-unused-variable */

import { TestBed, async, fakeAsync, tick } from '@angular/core/testing';
import { UserComponent } from './user.component';
import { UserService } from "./user.service";
import { DataService } from "../shared/data.service";

describe('Component: User', () => {

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [UserComponent]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(UserComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create the component', () => { 
    expect(component).toBeTruthy();
  });

  it('should use the user name from the service', () => { 
    let userService = fixture.debugElement.injector.get(UserService);
    expect(userService.user.name).toEqual(app.user.name);
  });

  it('should display the user name if user is logged in', () => {
    let fixture = TestBed.createComponent(UserComponent);
    let app = fixture.debugElement.componentInstance;
    app.isLoggedIn = true;
    fixture.detectChanges();
    let compiled = fixture.debugElement.nativeElement;
    expect(compiled.querySelector('p').textContent).toContain(app.user.name);
  });

  it('shouldn\'t display the user name if user is not logged in', () => {
    let fixture = TestBed.createComponent(UserComponent);
    let app = fixture.debugElement.componentInstance;
    fixture.detectChanges();
    let compiled = fixture.debugElement.nativeElement;
    expect(compiled.querySelector('p').textContent).not.toContain(app.user.name);
  });

  it('shouldn\'t fetch data successfully if not called asynchronously', () => {
    let fixture = TestBed.createComponent(UserComponent);
    let app = fixture.debugElement.componentInstance;
    let dataService = fixture.debugElement.injector.get(DataService);
    let spy = spyOn(dataService, 'getDetails')
      .and.returnValue(Promise.resolve('Data'));
    fixture.detectChanges();
    expect(app.data).toBe(undefined);
  });

  it('should fetch data successfully if called asynchronously', async(() => {
    let fixture = TestBed.createComponent(UserComponent);
    let app = fixture.debugElement.componentInstance;
    let dataService = fixture.debugElement.injector.get(DataService);
    let spy = spyOn(dataService, 'getDetails')
      .and.returnValue(Promise.resolve('Data'));
    fixture.detectChanges();
    fixture.whenStable().then(() => {
      expect(app.data).toBe('Data');
    });
  }));

  it('should fetch data successfully if called asynchronously', fakeAsync(() => {
    let fixture = TestBed.createComponent(UserComponent);
    let app = fixture.debugElement.componentInstance;
    let dataService = fixture.debugElement.injector.get(DataService);
    let spy = spyOn(dataService, 'getDetails')
      .and.returnValue(Promise.resolve('Data'));
    fixture.detectChanges();
    tick();
    expect(app.data).toBe('Data');

  }));
});