Angular JS Notes

Angular JS Notes

CLI

Generate

Using dash case

ng generate component new-custom-component

Directive

Additional behavior to DOM elements in HTML

Components

Used with a template.

NgModel

Adds two-way data binding to an HTML form element.

Method 1 – Without NgModel

<label for="without">without NgModel:</label>
<input
  [value]="js_var"
  (input)="js_var = getValue($event)"
  id="without"
/>

Method 2 – With NgModel

<label for="example-ngModel">[(ngModel)]:</label>
<input [(ngModel)]="js_var" id="example-ngModel" />

Method 3 – With NgModelChange Event

<label for="example-change">(ngModelChange)="...name=$event":</label>
<input
  [ngModel]="js_var"
  (ngModelChange)="js_var = $event"
  id="example-change"
/>

Method 4 – additional changes for variable

<label for="example-uppercase"
      >(ngModelChange)="setUppercaseName($event)"
      <input
        [ngModel]="js_var"
        (ngModelChange)="setUppercaseName($event)"
        id="example-uppercase"
      />
    </label>

NgClass

Adds and removes a set of CSS classes.

// CSS
.course {
	font-weight: bold;
	font-size: x-large;
}

.helpful {
	color: red;
}

.study,
.modified {
  font-family: "Brush Script MT", cursive;
  font-size: 2rem;
}

// HTML
<div class="helpful study course">Helpful study course</div>

// Turn css class/property based on true or false
<div [ngClass]="{ helpful: false, study: false, course: false }">
  Study course
</div>

NgClass using JS variable

currentClasses: Record<string, boolean> = {};

// HTML
<div [ngClass]="currentClasses">
  Check style based on CSS
</div>

NgStyle

Set multiple inline styles simultaneously, based on the state of the component.

<div [style.font-size]="isSpecial ? 'x-large' : 'smaller'">
  This div is x-large or smaller.
</div>
<div [style.color]="isSpecial ? 'red' : 'blue'">
This div is red or blue.
</div>

NgStyle using JS variable

<div [ngStyle]="currentStyles">
  This div is initially italic, normal weight, and extra large (24px).
</div>

Build-in structural directives

NgIf

To add or remove an element, bind *[ngIf](<https://angular.io/api/common/NgIf>) to a condition expression such as isActive ,or check if variable is null.

<app-item-detail *ngIf="isActive" [item]="item"></app-item-detail>

ng-template

defines a template that is not rendered by default.

<ng-template [ngIf]="currentItem">Add {{ currentItem.name }} with template</ng-template>

class.hidden

<div [class.hidden]="!isSpecial">Show with class</div>

NgFor

static items: Item[] = [
    new Item(
      0,
      'Teapot',
      'stout'
    ),
    new Item(1, 'Lamp', 'bright'),
    new Item(2, 'Phone', 'slim' ),
    new Item(3, 'Television', 'vintage' ),
    new Item(4, 'Fishbowl')
  ];

<div class="box">
  <div *ngFor="let item of items">{{ item.name }}</div>
</div>
<div *ngFor="let item of items; let i = index">
    {{ i + 1 }} - {{ item.name }}
  </div>

TrackBy

Reduce the number of calls your application makes to the server by tracking changes to an item list. With the *[ngFor](<https://angular.io/api/common/NgForOf>) trackBy property, Angular can change and re-render only those items that have changed, rather than reloading the entire list of items.

??

ng-container

Hosting a directive without a DOM element

Use [<ng-container>](<https://angular.io/api/core/ng-container>) when there’s no single element to host the directive.

<p>
  I turned the corner
  <ng-container *ngIf="hero">
    and saw {{hero.name}}. I waved
  </ng-container>
  and continued on my way.
</p>

ng-container with forms

<div>
  Pick your favorite hero
  (<label><input type="checkbox" checked (change)="showSad = !showSad">show sad</label>)
</div>
<select [(ngModel)]="hero">
  <ng-container *ngFor="let h of heroes">
    <ng-container *ngIf="showSad || h.emotion !== 'sad'">
      <option [ngValue]="h">{{h.name}} ({{h.emotion}})</option>
    </ng-container>
  </ng-container>
</select>

NgSwitch

// Javascript
num: number= 0;

// HTML
<div class='card'>
  <div class='card-header'>
    ngSwitch Example
  </div>
  <div class="card-body">
    Input string : <input type='text' [(ngModel)]="num" />
 
    <div [ngSwitch]="num">
      <div *ngSwitchCase="'1'">One</div>
      <div *ngSwitchCase="'2'">Two</div>
      <div *ngSwitchCase="'3'">Three</div>
      <div *ngSwitchCase="'4'">Four</div>
      <div *ngSwitchCase="'5'">Five</div>
      <div *ngSwitchDefault>This is Default</div>
    </div>
  </div>
</div>

Router

Basic

Associate a URL path with a component

Step 1 – add path in RouterModule

@NgModule({
  imports: [
    RouterModule.forRoot([
      { path: '', component: ProductListComponent },
      { path: 'products/:productId', component: ProductDetailsComponent },
    ])
  ],
})

Step 2 – for the hyperlink add routeLink

<a
  [title]="product.name + ' details'"
  [routerLink]="['/products', product.id]">
  {{ product.name }}
</a>

Step 3 – Implement route component in JS

import { Component, OnInit } from '@angular/core';
**import { ActivatedRoute } from '@angular/router';
import { Product, products } from '../products';**
export class ProductDetailsComponent implements OnInit {
  **product: Product | undefined;**
  constructor( **private route: ActivatedRoute** ) { }
  ngOnInit(): void {
    // First get the product id from the current route.
    **const routeParams = this.route.snapshot.paramMap;
    const productIdFromRoute = Number(routeParams.get('productId'));**

    // Find the product that correspond with the id provided in route.
    **this.product = products.find(product => product.id === productIdFromRoute);**
  }
}

Step 4 – Use ngIf in component HTML

<div *ngIf="product">
  <h3>{{ product.name }}</h3>
  <h4>{{ product.price | currency }}</h4>
</div>

Lazy Loading

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

Pipe

Use pipes to transform strings, currency amounts, dates, and other data for display

https://angular.io/guide/pipes

Dependency Injection

allows classes with Angular decorators, such as Components, Directives, Pipes, and Injectables, to configure dependencies that they need.

When a dependency is requested, the injector checks its registry to see if there is an instance already available there. If not, a new instance is created and stored in the registry.

Basic – create service

ng generate service cart

cart.service.ts

export class CartService {
  items: Product[] = [];

  addToCart(product: Product) {
    this.items.push(product);
  }
}

In component

import { CartService } from '../cart.service';
export class ProductDetailsComponent implements OnInit {
  constructor(
    private route: ActivatedRoute,
    private cartService: CartService
  ) { }
	addToCart(product: Product) {
    this.cartService.addToCart(product);
    window.alert('Your product has been added to the cart!');
  }
}

RxJS

Reactive Extensions for JavaScript

makes it easier to compose asynchronous or callback-based code

  • Converting existing code for async operations into observables
  • Iterating through the values in a stream
  • Mapping values to different types
  • Filtering streams
  • Composing multiple streams

https://angular.io/guide/rx-library

Communicating with backend services

communicate with a server over the HTTP protocol

https://angular.io/guide/http

Basic

app.module.ts

import { HttpClientModule } from '@angular/common/http';
@NgModule({
  imports: [
    HttpClientModule,
    ])
  ]
})

Inject the [HttpClient](<https://angular.io/api/common/http/HttpClient>) service into your service

cart.service.ts

import { HttpClient } from '@angular/common/http';
export class CartService {
  items: Product[] = [];
  constructor(private http: HttpClient) {}
	getShippingPrices() {
	    return this.http.get<{type: string, price: number}[]>('/assets/shipping.json');
	}

Get the data

shipping.component.ts

import { Observable } from 'rxjs';
import { CartService } from '../cart.service';
export class ShippingComponent implements OnInit {
  shippingCosts!: Observable<{ type: string, price: number }[]>;
	
constructor(private cartService: CartService) { }
  ngOnInit(): void {
    this.shippingCosts =  this.cartService.getShippingPrices();
  }
}

Use async pipe

shipping.component.html

<div class="shipping-item" *ngFor="let shipping of shippingCosts | async">
  <span>{{ shipping.type }}</span>
  <span>{{ shipping.price | currency }}</span>
</div>

Reactive forms

provide a model-driven approach to handling form inputs whose values change over time

https://angular.io/guide/reactive-forms

Basic

add FormsModule into appModule

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
  imports: [
    FormsModule,
    ReactiveFormsModule
  ]
})
export class AppModule { }

cart.component.ts

import { FormBuilder } from '@angular/forms';
export class CartComponent implements OnInit {
  checkoutForm = this.formBuilder.group({
    name: '',
    address: ''
  });
  constructor(private formBuilder: FormBuilder) { }
  onSubmit(): void {
    // Process checkout data here
    this.items = this.cartService.clearCart();
    console.warn('Your order has been submitted', this.checkoutForm.value);
    this.checkoutForm.reset();
  }
}

cart.compoent.html

<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="address">
      Address
    </label>
    <input id="address" type="text" formControlName="address">
  </div>
  <button class="button" type="submit">Purchase</button>
</form>