Before start testing method in components we initialize few things as below

  1. beforeEach method helps in initializing the values needed for testing
  2. describe are similar to JUnit class and it are similar to junit class methods which tests particular method in src code
  3. TestBed is needed while testing both component and html.You need to configure the TestBed before each test, adding any components, modules and services you need for the test. It’s just like configuring an regular @NgModule from scratch, but you just add what you need.
    import { async, TestBed } from '@angular/core/testing';
    
    beforeEach(async(() => {
      TestBed.configureTestingModule({
        declarations: [ AppComponent ],
        providers: [],
        imports: []
      })
      .compileComponents();
    }));
    
  4. Using TestBed.createComponent create component instance returns componentFixture Interface. componentFixture is a wrapper over component with additional methods needed for testing. fixture.componentInstance returns instance of component.
    beforeEach(() => {
    .
    //Returns Component Fixture
    let fixture = TestBed.createComponent(EmployeeComponent);
    
    //Get Instance of Component
    component = fixture.componentInstance;
    .
    .
    });
    
  5. fixture.detectChanges() would allow to check for change in DOM elements before expect or whenever it is referenced for value
  6. DebugElement, an interface which wraps native element instead of HTML element in idle scenario
  7. schemas:[NO_ERRORS_SCHEMAS] lets angular testing module to ignore unknown tags in html during testing. Suppose you have used router tags in html
    and angular could not recognize the router tag since routerTestingModule is not imported you can use this tag as below to avoid errors.

    beforeEach(() => {
         TestBed.configureTestingModule({
          declarations: [ EmployeeComponent]
          schemas:[NO_ERRORS_SCHEMAS]
         }).compileComponents();
    
        //Testbed to create fixture for component
        fixture = TestBed.createComponent(EmployeeComponent);
    
        //Using fixture to create component and service 
        component = fixture.componentInstance;
        empService = TestBed.inject(EmpserviceService);    
     });
    
    

Simple testing with matchers

  1. toBeTruthy tells the component is created successfully
  2. toBe checks for equality of value
  3. toEqual method does object comparison
  4. toContain method checks whether value is available in array
fit('Simple component testing', ()=>{
  //Checks whether component has been created
  expect(component).toBeTruthy();

  //Checks whether value returned by function are same
  expect(component.getGender(true)).toBe('Male');

  //Checks objects are equal and array contain that element
  var Names = ['Name1', 'Name2', 'Name3'];
  expect(Names).toEqual(['Name1', 'Name2', 'Name3']);
  expect(Names).toContain('Name2');
});

Checking DOM Elements

  1. nativeElement – provides the access to DOM element.This is same as Javascript DOM Element we use for DOM Manipulation.Using nativeElement you can
    access all the API methods provided vy Javascript for DOM manipulation like QuerySelector
  2. fixture.detectChanges() – updates the DOM Element after setting the value from testing component. This is similar to refresh once the component value is set the html should be refreshed.
  3. debugElement– debugElement is similar to nativeElement which has wrapper with some additional methods.It has query, queryAll, queryNode methods
    debugElement inturn calls nativeElement to get the values.fixture.debugElement returns the root debugElement from which we query for the nativeElement.

    .
    .
    fixture.debugElement.query(By.css('a')).nativeElement.textContent)
    fixture.debugElement.query(By.css('#ContactUsId')).nativeElement.textContent)
    fixture.debugElement.query(By.css('.ContactUsId')).nativeElement.textContent)
    .
    .
    .
    
  4. The below statement end up the same anchor tag
    .
    
    fixture.debugElement.query(By.css('a')).nativeElement.textContent)
    fixture.nativeElement.querySelector('a').textContent
    .
    

Angular 6 – NullInjectorError: No provider for HttpClient in unit tests
If you don’t import HttpClientModule (or HttpClientTestingModule) there, HttpClient won’t work because Angular doesn’t know about it. It doesn’t matter that you added HttpClientModule to, say, AppModule. It needs to be in TestBed.configureTestingModule.

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import {HttpClientModule} from '@angular/common/http';

describe('myService', () => {
.
.
.
});

Cross-Origin Resource Sharing (CORS)
The browser’s same-origin policy blocks reading a resource from a different origin. This mechanism stops a malicious site from reading another site’s data. The same-origin policy tells the browser to block cross-origin requests. When you want to get a public resource from a different origin, the resource-providing server needs to tell the browser “This origin where the request is coming from can access my resource”. The browser remembers that and allows cross-origin resource sharing.

In angular when front end request origin is different the browser stops processing response from the server.

Request has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header
is present on the requested resource.

Same-Origin Policy

  1. The same-origin policy fights one of the most common cyber-attacks out there: cross-site request forgery.
  2. If you have logged into FB your info would be stored in Cookie and would be tagged along when the request is made every time
  3. Every time you re-visit the FB tab and click around the app, you don’t have to sign in again. Instead, the API will recognize the stored session cookie upon further HTTP requests.
    The only trouble is that the browser automatically includes any relevant cookies stored for a domain when another request is made to that exact domain.
  4. Say you clicked on a particularly trick popup ad, opening evil-site.com.The evil site also has the ability to send a request to FB.com/api. Since the request is going to the FB.com domain, the browser includes the relevant cookies. Evil-site sends the session cookie, and gains authenticated access to FB. Your account has been successfully hacked with a cross-site request forgery attack.
  5. At this point, browser will step in and prevent the malicious code from making an API request like this. It will stop evil-site and say “Blocked by the same-origin policy.

How Browser works underhood?

  1. The browser checks for the request origins of the web application and the Server origins response match
  2. The origin is the combination of the protocol, host, and port.
          For example, in https://www.FB.com, 
    	   the protocol is https://, 
    	   the host is www.FB.com, and 
    	   the hidden port number is 5400 (the port number typically used for https).
    
  3. To conduct the same-origin check, the browser accompanies all requests with a special request header
    that sends the domain information to receiving server
  4. For example, for an app running on localhost:3000, the special request format looks like this:
    Origin: http://localhost:3000
    

    Reacting to this special request, the server sends back a response header. This header contains an Access-Control-Allow-Origin key,
    to specify which origins can access the server’s resources. The key will have one of two values:

    One: the server can be really strict, and specify that only one origin can access it:
    Access-Control-Allow-Origin: http://localhost:3000

    Two: the server can let the gates go wide open, and specify the wildcard value to allow all domains to access its resources:
    Access-Control-Allow-Origin: *

  5. Once the browser receives this header information back, it compares the frontend domain with the Access-Control-Allow-Origin
    value from the server. If the frontend domain does not match the value, the browser raises the red flag and blocks the API
    request with the CORS policy error.

The above solution works for development. How about in production.

To address such issues, the proxy is used between client and server.

Request from Client -> Proxy Server -> Server 
Respose from Server -> Proxy Server(appends origin) -> Client

Now what the proxy does is it appends the s Access-Control-Allow-Origin: * in the header before the response is sent to the client browser

We use property binding to pass value from component to form element in html and event binding to pass value from html to angular component.

  1. In the below code when we use [value] to get the value from component to html
  2. The same way we use (input) to get back value on event like change of name text
  3. {{employee.Name}} is used to display the value. You can remove [value] or (input) to check the behavior.
  4. Instead of this we can use ngModule by importing FormsModule which takes care of both propery and data binding

empform.html

<form>
<input type="text" [value]="employee.Name" (input)="employee.Name=$event.target.value" />
{{employee.Name}}
</form>

EmployeeModel.ts

export class Employee {
  private _Name: String;

  constructor(name: String) {
    this._Name = name;
  }
}

EmployeeController.ts

export class AddemployeeComponent implements OnInit {
.
.
  public employee: Employee;

  constructor() {
    this.employee = new Employee('Mugilvannan');
  }
.
.
}

  1. For NgModeul to work name attribute(i.e. employeeName) is mandatory in form field.
    Otherwise the value wont be reflected on change
  2. [ngModel] is for value binding and (ngModelChange) is for event binding. Both can be grouped in to format called banana-in-a-box. [(ngModel)]
  3. For using ngModel, FormsModule should be added to app.module.ts
  4. So when to use expanded syntax of ngModel. There would be times where you want to change the text into uppercase or lowercase once it is entered into textbox or formfields. In suchcase we should call an event which does it. At that time you would use (ngModelChange) instead of [(ngModel)].

addemployee.component.html

  <form>
    <table style="border-collapse:collapse;" border="1" cellpadding="5">
      <tbody>
        <tr>
          <td>Name</td>
          <td><input type="text" name="employeeName" [ngModel]="employee.Name" (ngModelChange)="employee.Name=$event" /></td>
        </tr>
        <tr>
          <td colspan="2">
            <input type="submit" value="Add Employee" (click)="employee.Name='test'" />
          </td>
        </tr>
      </tbody>
    </table>
  </form>
  {{employee.Name}}

addemployee.component.html – Banana-in-a-Box format

.
.
<td><input type="text" name="employeeName" [(ngModel)]="employee.Name"/></td>
.
.
  1. Services are mostly used in displaying datas from APIs
  2. To generate a new service use ng generate service Services/SERVICE_NAME
  3. services are injectable because they would be mostly called by other components
  4. Injection of services can happen at three level
    • AppModule – Same Instance of Service Injected would be available across application
    • AppComponent – Same Instance of Service Injected at this level would be available in this component and all child component
    • Any Other Component – Same Instance of Service Injected would be available to this component and child component(not to parent component)
  5. @Injectable is not needed if the Service is added in app.modules.ts

aboutus.component.ts

.
.
constructor(private objApi:ApiService) { 
    this.objApi.getDataFromRest();
  }
.
.

api.service.ts

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

@Injectable({
  providedIn: 'root'
})
export class ApiService {

  constructor() { }

  getDataFromRest()
  {
    return console.log("Data from Rest Method");
  }
}

If Else
aboutus.component.ts

export class AboutusComponent implements OnInit {
  showMsg: boolean = true;
  .
  .
  .
}

aboutus.component.html

<p *ngIf='showMsg; else elseBlock'>aboutus works from If block!</p>

<ng-template #elseBlock>
    <p>aboutus works from else block!</p>
</ng-template>

Output

aboutus works from If block!

Switch Case
aboutus.component.ts

export class AboutusComponent implements OnInit {
  .
  .
  color : string =  'pink';
  .
  .
}

aboutus.component.html

<div [ngSwitch] = 'color'>
    <p *ngSwitchCase="'blue'">Its Blue Color</p>
    <p *ngSwitchCase="'red'">Its Red Color</p>
    <p *ngSwitchCase="'green'">Its Green Color</p>    
    <p *ngSwitchDefault>Its Default Color</p>    
</div>

Output

Its Default Color

For Angular routing the routing option should have been enabled while starting new project.

  1. To define a link you need to use routerLink instead of href followed by route in other side of equals like one in app.component.html
      <ul>
        <li><a routerLink="/">Home</a></li>
        <li><a routerLink="/aboutus">About Us</a></li>
        <li><a routerLink="/services">Services</a></li>
        <li><a routerLink="/contactus">Contact Us</a></li>
      </ul>
    
  2. The list of routes needs to be defined in app-routing.module.ts. It is defined inside routes array list with path and component as key value pair like one below app-routing.module.ts
    const routes: Routes = [
      {path:'aboutus', component: AboutusComponent},
      {path:'services', component: ServicesComponent},
      {path:'contactus', component:ContactComponent}
    ];
    
  3. The path and one defined assigned to routerLink in html should be same. The component is the name of the component class which represent individual page of application
  4. If you are using absolute path then it would be /PATH which takes reference of component to be loaded form root url. If you are using relative path the it would be PATH (or) ../PATH (or) ../../PATH. Incase you are using relative path clicking the link of the same page from the page you are in should throw an error(Could not be verified)
  5. Navigating to link could be acheived by two ways
    • Using RouterLink in a tags
    • Using router navigate method in ts code
  6. routerLink always knows which route is currently loaded.router navigate method does not which route is presently loaded. So we always use activateRoute and pass relativeTo as parameter and pass relative URL as parameter

app-routing.module.ts

import { NgModule, Component } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {AboutusComponent} from './aboutus/aboutus.component';
import {ServicesComponent} from './services/services.component';
import {ContactComponent} from './contact/contact.component';


const routes: Routes = [
  {path:'aboutus', component: AboutusComponent},
  {path:'services', component: ServicesComponent},
  {path:'contactus', component:ContactComponent}
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

app.component.html

<style>
ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  overflow: hidden;
  background-color: #333;
}

li {
  float: left;
}

li a {
  display: block;
  color: white;
  text-align: center;
  padding: 14px 16px;
  text-decoration: none;
}

/* Change the link color to #111 (black) on hover */
li a:hover {
  background-color: #111;
}

.active {
  background-color: #4CAF50;
}

li {
  border-right: 1px solid #bbb;
}

li:last-child {
  border-right: none;
}
</style>
<div class="content" role="main">
  <ul>
    <li><a routerLink="/">Home</a></li>
    <li><a routerLink="/aboutus">About Us</a></li>
    <li><a routerLink="/services">Services</a></li>
    <li><a routerLink="/contactus">Contact Us</a></li>
  </ul>
</div>
<router-outlet></router-outlet>

Code Snippets – Table of Contents

  1. Builtin Angular Directives

    1. Attribute Directive – NgStyle, NgClass
    2. Structural Directive – *NgIf, *NgFor, *NgSwitch

Attribute Directive – ngClass and ngStyle
ngClass

  1. For using ngClass the styling should be in JSON Obect
  2. Advantage of using ngClass is applying more than one class to the DOM Element unlike class
  3. In the below code you see class which applies present or absent based on one true or false returned by getResult function
  4. In the registration.component.ts we have declared a JSON object which applies 2 classes present and normal or absent and bold based on true or false returned by getStatus(method)

Styling using class
registration.component.html

.
.
<td [class]="getStatus()?'present':'absent'">{{objStudent.science}}</td>
.
.
.

Styling using ngClass
registration.component.html

.
.
<td [ngclass]="cssStyle">{{objStudent.science}}</td>
.
.
.

registration.component.ts

.
.
export class RegistrationComponent implements OnInit { 
  public cssStyle;  
 
  ngOnInit() {
     this.cssStyle = {
       "present" : getStatus(),
       "absent"  : !getStatus(),
       "normal"  : getStatus()
       "bold"    : !getStatus(),       
     };
  }
}

.
.
.

ngStyle

  1. ngStyle is to apply style directly instead of defining style using class
  2. Same registration.component.ts has been modified to take style attributed such as color and weight

registration.component.ts

.
.
export class RegistrationComponent implements OnInit { 
  public cssStyle;  
 
  ngOnInit() {
     this.cssStyle = {
       "background-color"  : getStatus()?"green":"red",
       "font-weight"       : getStatus()?"normal":"bold"       
     };
  }
}
.
.
.

There is an alternative for both above [class] and [ngClass] as below

.
.
<td [class.positive]="getStatus()" [class.negative]="!getStatus()">{{objStudent.science}}</td>.
.

Similarly for [ngStyle] as below

.
.
<td [style.background-color]="getStatus()?'green':'red'">{{objStudent.science}}</td>.
.

Structural Directive – ngIf, ngFor and ngSwitch
ngIf

  1. In the below code we decide the words to be displayed based on the value returned by getStatus(objStudent) method
  2. Pass would be displayed if true or else fail would be returned
.
.
<span *ngIf="getStatus(objStudent)">Pass</span>
<span *ngIf="!getStatus(objStudent)">Fail</span>
.

ngFor

  1. In the below code we use *ngFor loop to iterate over array of student object
  2. We are generating serial no for first column by adding 1 to variable i and displaying name of student in second column
  3. *ngFor has other loacl values apart from indes such as even, odd, first, last based on which manipulations could be carried out

registration.component.ts

.
.
export class RegistrationComponent implements OnInit {
  public arrStudent:Array<Student>;

  ngOnInit() {
     this.arrStudent = [new Student(101, 'Mugil', 31, 74, 65,55,64,84),
                        new Student(102, 'Manasa', 26, 31, 65,55,86,84),
                        new Student(103, 'Kavitha', 27, 90, 65,60,84,46),
                        new Student(104, 'Renu', 28, 31, 65,55,84,46),
                        new Student(105, 'Joseph', 23, 31, 65,55,89,84)];

  }
.
.
}

registration.component.ts

.
.
<tr>
    <th>Sno</th>
    <th>Student ID</th>
</tr>
<tbody>
  <tr *ngFor="let objStudent of arrStudent; index as i;">
     <td>{{i+1}}</td>
     <td>{{objStudent.studentId}}</td>
     .
     .
     .
     .
  </tr>
</tbody>
.
.

Now let’s see a simple example of applying a different color to text based on odd and even rows

registration.component.ts

.
.
<tr *ngFor="let objStudent of arrStudent; index as i;odd as isOdd; even as isEven" [class]="isOdd?'odd':'even'">
     .
     <td>{{i+1}}</td>
     <td>{{objStudent.studentId}}</td>
     .
</tr>

the same code can be written as below where the only difference is styles are applied seperately evaluating for both odd and even.
registration.component.ts

.
.
<tr *ngFor="let objStudent of arrStudent; index as i;odd as isOdd; even as isEven" [class]="isOdd" [class.even]="isEven">
     .
     <td>{{i+1}}</td>
     <td>{{objStudent.studentId}}</td>
     .
</tr>

We can define the template directly in a component instead of giving the templateURL using a template and define styleURL instead of styles.

registration.component.ts

.
.
@Component({
  selector: 'app-registration',
  template: '<tr>
              <td>{{objStudent.studentId}}</td>
              <td>{{objStudent.studentName}}</td>
            </tr>',
  styleUrls: ['./registration.component.css']
})
.
.
.

registration.component.ts

.
.
@Component({
  selector    : 'app-registration',
  templateURL : 'app-registration.html',
  styles      : ['
                   .present
                   {
                      background-color: greenyellow;
                   }

                   .absent
                   {
                      background-color: #fc8674;
                   }
                ']
})
.
.
.

Interpolation
app.component.ts

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'schoolApp';
}

registration.component.html

<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
</div>

Looping through Model Object set in component and Printing in HTML Page
Student.ts

export class Student {
   public isPresent:boolean=true;

   constructor(public studentId:number,
               public studentName:string,
               public studentAge:number,
               public studentGender:boolean){}
               

    getAttendance():string{
       if(this.isPresent==true)
        return "P";
       else 
        return "A";
    }           
}

registration.component.ts

import { Component, OnInit } from '@angular/core';
import {Student} from '../model/student';

@Component({
  selector: 'app-registration',
  templateUrl: './registration.component.html',
  styleUrls: ['./registration.component.css']
})
export class RegistrationComponent implements OnInit {
  public arrStudent:Array<Student>;
  constructor() { }

  ngOnInit() {
     this.arrStudent = [new Student(101, 'Mugil', 31, true),
                        new Student(102, 'Manasa', 26, false),
                        new Student(103, 'Kavitha', 27, false),
                        new Student(104, 'Renu', 28, true),
                        new Student(105, 'Joseph', 23, true)];
  }

  getGender(Student):string
  {
    if(Student.studentGender==true)
     return "M";
     else
     return "F";
  }
}

registration.component.html

<style>
 .even
    {
        background-color: rgb(235, 235, 235);
    }

    .odd
    {
        background-color : #ffffff;
    }
</style>
<table cellpadding="5">
    <thead>
  <tr>
    <th>Sno</th>
    <th>Student ID</th>
    <th>Name</th>
    <th>Age</th>
    <th>Gender</th>
    <th>Attendance</th>
  </tr>
</thead>
<tbody>
  <tr *ngFor="let objStudent of arrStudent; index as i;even as isEven;odd as isOdd" [class]="isEven?'even':'odd'">
     <td>{{i+1}}</td>
     <td>{{objStudent.studentId}}</td>
     <td>{{objStudent.studentName}}</td>
     <td>{{objStudent.studentAge}}</td>
     <td>{{ getGender(objStudent) }}</td>
     <td [class]="objStudent.isPresent?'present':'absent'">{{objStudent.getAttendance()}}</td> 
  </tr>
</tbody>
</table>


	

Bootstrapping Angular Application

  1. Then entry point to every Angular application is the main.ts file which contains this last line:
     
     platformBrowserDynamic().bootstrapModule(AppModule); 
    
  2. The platformBrowserDynamic() part of this line of code indicates that we are about to boot Angular in a browser environment. As Angular can be used in Javascript host environments asides the browser (e.g. on the server or in a web worker), its thus imperative that we specify the environment in which our App is to be booted.
  3. The bootstrapModule() function helps bootstrap our root module taking in the root module as its argument.
  4. AppModule is our root module which is the entry module for our application, this can actually be any of the modules in our application but by convention AppModule is used as the root module.
  5. In our AppModule, we then need to specify the component that will serve as the entry point component for our application. This happens in our app.module.ts file where we import the entry component (conventionally AppComponent) and supply it as the only item in our bootstrap array inside the NgModule configuration object.
     
     bootstrap:[AppComponent]
    

To put it short

  1. platformBrowserDynamic() to determine the Broswer or platform in which your angular app is about to run
  2. bootstrapModule() function to boot your entry module(app.module.ts) by supplying the module as an argument.
  3. app.module.ts is the root module that would specify the entry point component in the module configuration object.

How angular Works Internally