The purpose of this article is to get a quick start on Angular development, or to get a quick overview of angular development considerations

Environment set up

  1. Scaffolding installation: NPM i-g@angular/CLI
  2. New project: ng new my-app

If scaffolding installation error, force clean NPM cache and reinstall

Components and Templates

When you download the official solution list, you may not be familiar with the directory. Don’t focus on that for now. This article focuses on how to get started on an Angular project quickly.

Understand the template expression context

Context variables in expressions are composed of three types:

  1. Template variables (template $event object, template input variable (let hero), and template reference variable (#heroForm))
  2. Context variables of directives (attributes in directives)
  3. Component member variables (component real columns)

When the same expression variables are present in precedence order: template variables >> context variables of directives >> member variables of components

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

//my-app/src/app/app.component.ts
@Component({
  selector: 'app-root'.templateUrl: './app.component.html'.styleUrls: ['./app.component.css']})export class AppComponent {
  private data0:Number = 1121; 
  data1 = '<div>dddddd</div>';
  data2 = {
    aaa:222
  };
  data3(){
  };
  data4 = null;
  data5 = undefined;
  data6 = [1.2.3]}Copy the code
<div>
  <div>Data0: {{data0}}</div>
  <div>Data1: {{data1}}</div>
  <div>Data2: {{data2}}</div>
  <div>Data3: {{data3}}</div>
  <div>Data4: {{data4}}</div>
  <div>Data5: {{data5}}</div>
  <div>Data6: {{data6}}</div>
  <div>Data7: {{data7}}</div>
</div>

<!-- 
	data0 :1121
	data1 :<div>dddddd</div>
	data2 :[object Object]
	data3 :function () { }
	data4 :
	data5 :
	data6 :1,2,3
	data7 : 
-->
Copy the code

Understand HTML attributes and DOM properties

Let’s start with an example

// HTML: 
var outPutVal = function(){
    console.log('the getAttribute:',inO.getAttribute('value'));
    console.log('inO.value:',inO.value);
}

window.onload = function(){
    var inO = document.querySelect('input');
    outPutVal(inO);
    / / the getAttribute: a
    //inO.value: a
    document.onclick = function(){
        // Manually enter value as aaAAA and print it
        outPutVal(inO);
        / / the getAttribute: a
        //inO.value: aaaaa}}Copy the code

The above native JS shows the difference between HTML attributes and DOM properties:

  1. A few HTML attributes and properties have a 1:1 mapping, such as ID.
  2. Some HTML attributes, such as Colspan, have no corresponding property.
  3. Some DOM properties have no corresponding attribute, such as textContent.

Angular template bindings work with properties and events, not attributes

Special attribute binding

[attr.aria-label]="actionName"
<td [attr.colspan] ="1 + 1">
Copy the code

instruction

There are three types of instructions:

  1. Component – A directive that owns a template
  2. Structural directives – directives that change the DOM layout by adding and removing DOM elements
  3. Attribute directives – directives that change the appearance and behavior of elements, components, or other directives.

Attribute instructions

  1. ngClass
  2. ngStyle
  3. ngModel

Structural instruction

  1. ngIf
  2. ngFor
  3. ngSwitch
Ng-template * syntax
<div *ngIf="hero" class="name">{{hero.name}}</div>
-----------------------------------
<ng-template [ngIf] ="hero">
  <div class="name">{{hero.name}}</div>
</ng-template>
Copy the code
<div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd] ="odd">
  ({{i}}) {{hero.name}}
</div>
-----------------------------------
<ng-template ngFor let-hero [ngForOf] ="heroes" let-i="index" let-odd="odd" [ngForTrackBy] ="trackById">
  <div [class.odd] ="odd">({{i}}) {{hero.name}}</div>
</ng-template>
Copy the code

Before rendering a view, Angular replaces the < ng-template > and its wrapped contents with a comment

ng-container

Sibling elements are grouped together and ng-template wraps inner elements without side effects

What do you mean no side effects? (Example: breaking HTML structure!) :

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

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

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

Component – Special directives (directives that own templates)

Ng g C Components /A Create A componentCopy the code

Several ways in which components communicate

1. Input attribute @input () (parent component passes data to child component)
//a.component.ts
  @Input()
  inAttr:String;


  private _name:String = ' ';
----------------------------------------------------
  @Input()
  set inAttr2(name:String) {this._name = name;
  }
  
  get inAttr2():String{
    return this._name;
  }
Copy the code
2. Output attribute @output () (child passes data to parent)
// In the child component
@Output()
myEvent:EventEmitter<DataType> = new EventEmitter();

this.myEvent.emit(Data);

// In the parent component
(myEvent)="myHandleEvent($event)"
myHandleEvent(Data:DataType){
    
}
Copy the code
3. Man-in-the-middle mode (sibling components pass values through common parent components)
4. Parent component gets child component reference #child (can only be used in component templates)
5. @viewChild () inserts child components (used in component classes)
  1. Injected child components can only be accessed after Angular displays the parent component view (in the ngAfterViewInit lifecycle)
  2. Angular’s one-way data flow rules prevent updating the parent component view in the same cycle. The app is forced to wait another round before displaying the number of seconds.
  3. Workaround: Use setTimeout() to change the data
@ViewChild(ChildComponent)
private childComponent: ChildComponent;

ngAfterViewInit() {
    setTimeout((a)= > this.seconds = (a)= > this.childComponent.changeData, 0);
}
Copy the code
6. Change data through services (used in any component structure)

Custom instruction

ng g d myDirective/demo
Copy the code
  1. Attribute instruction

ElementRef: Wrapper for a native element in the view.

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[appDemo]'
})
export class DemoDirective {
  // The constructor declares the element to be injected, el: ElementRef.
  constructor(private el:ElementRef) { }
  // Register events
  @HostListener('click')
  show(){
    console.log(this.el.nativeElement);
    console.log(this.ss);
  }
  // Instruction parameter, when the parameter name and instruction name are the same, can be directly assigned to the instruction
  @Input()
  ss:String = 'aaa';
}

Copy the code
<button appDemo [ss] ="bbb">click me</button>
Copy the code
  1. Structural instruction

TemplateRef: get the contents of < ng-template >

ViewContainerRef: Accesses the view container

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
  // The first time true is passed, no if branches are executed to improve performance
  private hasView = false;

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) { }

  @Input() set appUnless(condition: boolean) {
    if(! condition && !this.hasView) {
      // Instantiate an attempt and insert it into the container
      this.viewContainer.createEmbeddedView(this.templateRef);
      this.hasView = true;
    } else if (condition && this.hasView) {
      this.viewContainer.clear();
      this.hasView = false; }}}Copy the code

The pipe

You can think of a pipe as an operator that processes data and then displays it, as in:

<p>{{ birthday}}</p>
<p>{{ birthday | date }}</p>
<! -- Chain call pipe -->
<p>{{ birthday | date | uppercase}}</p>
Copy the code

Angular built-in pipes:

DatePipe, UpperCasePipe, LowerCasePipe, CurrencyPipe and PercentPipe…….

Custom pipes

import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'exponentialStrength'})
export class ExponentialStrengthPipe implements PipeTransform {
  transform(value: number, exponent: string): number {
    let exp = parseFloat(exponent);
    return Math.pow(value, isNaN(exp) ? 1: exp); }}Copy the code

Pure pipe and impure pipe

  1. Angular executes a pure pipe only if it detects a pure change in the input value. Pure changes are changes to primitive type values (String, Number, Boolean, Symbol) or changes to Object references (Date, Array, Function, Object).

  2. Angular performs impure pipes during each component’s change detection cycle. Impure pipes may be called many times, as often as each keystroke or mouse movement.

@Pipe({
  name: 'flyingHeroesImpure'.pure: false
})
export class FlyingHeroesImpurePipe extends FlyingHeroesPipe {}
Copy the code

Dependency injection

Dependency injection is a way to achieve inversion of control by surrendering the creation of objects, and its benefits can be seen in real development, as described below

Angular implements inversion of control through dependency injection

Benefits of dependency injection:

Dependency injection lets you write code in a loosely-coupled way that is easy to debug:

Here’s an example:

When your service is divided into development version and online version, you may need two different services devDataSevice and proDataSevice. When you do not use dependency injection, you need to create these two objects in multiple components to use the two services. When switching between the online environment and the test environment, You need to change the code in multiple components, but with dependency injection you can change the service in all components by changing the code in the provider, which greatly reduces the coupling of the code and improves maintainability.

Start by creating a service

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

@Injectable({
  providedIn: 'root',})export class HeroService {
  constructor() {}}Copy the code

Service provider (injector)

Where to write service provider:

  1. Metadata options for providedIn in the @Injectable() decorator of the service itself

    The value of providedIn can be ‘root’ or a specific NgModule

  2. Providers metadata option in the @NgModule() decorator of the NgModule

  3. Providers metadata option in the @Component() decorator of the Component

  4. Providers metadata option (element-level injector) in the @Directive() decorator

Providers:

provider:[ProductService]
provider:[{provide:ProductService,useClass:ProductService}]
provider:[{provide:ProductService,useClass:AnotherProductService}]
provider:[{provide:ProductService,useFactory:(Parameters of A) = >{return ob},deps:[parameter A]}] provider:[{provide:"IS_DEV_ENV".useValue: {isDev:true}}]
Copy the code

The injector bubbles

  1. Angular tries to find the component’s own injector
  2. If the component’s injector doesn’t find a provider, it looks for its parent’s injector until Angular finds a valid injector or exceeds the ancestor location in the component tree.
  3. Angular throws an error if the ancestor in the component tree is not found.

Injection service:

In the constructor, inject:

construct(private productService:ProductService){... };Copy the code
  1. @optional () is a decorator for productService, set to null if the provider of the service cannot be found
  2. The @host () decorator disallows searches above the Host component. The host component is usually the one requesting the dependency. However, when this component projects into a parent component, that parent becomes the host.
  3. Inject() User-defined providers
  4. @self () and @skipself () to modify the provider’s search

@ presents/router routing

  1. Set the base tag to tell the route how to synthesize the navigation
<! Add <base href="/"> to the head tag in index.html to tell the route how to compose the navigation URL-->
<base href="/">
Copy the code
  1. Importing route Configuration
//app.module.ts
// Import the routing core module
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
  {path:'* *'.component:AComponent}
];

@NgModule({
  ...
  imports: [RouterModule.forRoot(routes)]
  ...
})
export class AppModule {}Copy the code

Routes Describes how to configure Routes

  1. Path “**” indicates all matches

  2. RedirectTo “means the path to be redirected”

  3. PathMatch “Full” indicates the matching degree

  4. Component represents the component to display

  5. Data transfer

  6. Zi lu by children: []

  7. canActivate:[PermissionGuard]

  8. canDeactivate:[FocusGuard]

  9. resolve:{Stock:StockResolve}

  10. Outlet auxiliary routing

  11. Sets the navigation output position

<router-outlet></router-outlet>
<! -- Routed components go here -->
Copy the code

Routing hop

  1. Declarative jump
<a [routerLink] ="['/path']" routerLinkActive="active">routelink</a>
<a [routerLink] ="['./path']">routelink</a>
<a [routerLink] ="['{outlets:{aux:'aaa'}}']">routelink</a>Secondary routing http://localhost:4200/a(aux:aaa)Copy the code
  1. Imperative jump

Navigate with navigateByUrl()

Routing data transfer:

/ / 1.
[routerLink] = "['/path',1]"
//http://localhost:4200/path/1
// this.routeInfo.snapshot.queryParams
/ / 2.
[routerLink]="['/b',1]" [queryParams]="{id:3}"
// http://localhost:4200/b/1? id=3
// this.routeInfo.snapshot.params
/ / 3.
{path:'a'.component:AComponent,data: {id:Awesome!}} 
//this.routeInfo.snapshot.queryParams
//this.routeInfo.snapshot.data
Copy the code

ActivatedRoute commonly used: this.routeinfo see above

The guards routing

1.canActivate

export class PermissionGuard implements CanActivate{
  canActivate(){
    let hasPemission:boolean = Math.random() < 0.5;
    returnhasPemission; }}Copy the code

2.canDeactivate

export class FocusGuard implements CanDeactivate<CComponent>{
  canDeactivate(component:CComponent){
    if(component.isFoucs){
      return true;
    }else {
      return confirm('Don't you care? '); }}}Copy the code

3. Resolve before reading data

@Injectable()
export class StockResolve implements Resolve<Stock>{
  constructor(
    private route:Router
  ){}
  resolve(route:ActivatedRouteSnapshot,state:RouterStateSnapshot){
      return new Stock(1.'name'); }}Copy the code

Lifecycle hook

Hook functions that are triggered when an Angular component or directive is created, updated, or destroyed

The order in which hook functions are executed

  1. Constructor this is not the lifecycle hook, but it must be executed first
  2. NgOnChanges Called when an input property is assigned (changes to immutable objects)
  3. NgOnInit first displays the data binding and sets the input properties of the directive/component
  4. NgDoCheck is called immediately after ngOnChanges() and ngOnInit() during each change detection cycle
  5. NgAfterContentInit is called after the external content is projected into the component/directive view
  6. Called after ngAfterContentChecked projects changes to the content of the component
  7. Called after ngAfterViewInit initializes the component view and its child views
  8. Called after ngAfterViewChecked component view and child view change detection
  9. NgOnDestroy called before the directive/component is destroyed

Initialization phase

//1.constructor 
//2.ngOnChanges
//3.ngOnInit
//4.ngDoCheck
//5.ngAfterContentInit
//6.ngAfterContentChecked
//7.ngAfterViewInit
//8.ngAfterViewChecked
Copy the code

Phase change

//1.ngOnChanges
//2.ngDoCheck
//3.ngAfterContentChecked
//4.ngAfterViewChecked
Copy the code

Component destruction phase

//1.ngOnDestroy
// Changes when the route changes
Copy the code

ngAfterViewInit,ngAfterViewChecked

  1. The parent component is assembled until the child component is assembled
  2. Components are called after trying to assemble
  3. View data cannot be changed in this method

NgAfterContentInit ngAfterContentChecked, projection

1. The child component<div>
  <ng-content></ng-content>
</div>2. The parent component<SComponent>
    <! -- Whatever is written here is projected onto child components -->
</SComponent>
Copy the code

The form

  1. ReactiveFormsModule reactive forms
  2. FormsModule is a template form

Template form

  1. Angular automatically adds ngForm to the form, or ngNoForm if it’s not handled by Angular
  2. In the form with # myForm = “ngForm”, can be used in the page {{myForm. Value | json}} to detect form have ngModule value object called name value

The corresponding FormGroup NgForm

The corresponding FormControl ngModel

The corresponding FormArray ngModelGroup

<form #myForm="ngForm" action="/regist" (ngSubmit) ="createUser(myForm.value)" method="post">
  <div>
    <input ngModel name="a" type="text" required pattern="[a-zA-Z0-9]+">
  </div>
  <div>
    second:<input ngModel #second="ngModel" name="a" type="text" required pattern="[a-zA-Z0-9]+">
  </div>
  <div>
    <input ngModel name="b" type="text" required pattern="[a-zA-Z0-9]+">
  </div>
  <div ngModelGroup="tow">
    <input ngModel name="a" type="text">
    <input ngModel name="b" type="text">
  </div>
  <button type="submit">submit</button>
</form>
<div>
  {{myForm.value | json}}
  <br>{{second. Value}}</div>
Copy the code

Reactive form

private nickName = new FormControl('tom');
private passwordInfo = new  FormGroup({
  password: new FormControl(),
  passwordConfirm:new  FormControl()
});
private email = new FormArray([
    new FormControl('[email protected]'),
    new FormControl('[email protected]')]);Copy the code

FormControl

Manages the value and validity status of individual form controls

FormGroup

Manages the value and validity state of a set of AbstractControl instances

FormArray

Manages the value and validity state of a set of AbstractControl instances

<form [formGroup] ="formModel" action="/regist" (Submit) ="createUser()" method="post">
   <input  formControlName="nikname">
   <ul formArrayName="emails">
      <li *ngFor="let email of formModel.get('emails').controls; let i = index;">
        <input [formControlName] ="i">
      </li>
    </ul>
    <button >Increase the email...</button>
   <input  formControlName="emails">
   <div formGroupName="passwordInfo">
      <input formControlName="password">
      <input formControlName="passwordConfirm">
    </div>
</form>
Copy the code

FormBuilder shortcut syntax

private formModel:FormGroup;
private fb:FormBuilder = new FormBuilder();
/*this.formModel = new FormGroup({ nikname:new FormControl(), emails:new FormArray([ new FormControl() ]), mobile:new FormControl(), passwordInfo:new FormGroup({ password:new FormControl(), passwordConfirm:new FormControl() }) }); * /
this.formModel = this.fb.group({
  nikname: [' '].emails:this.fb.array([
      [' ']]),mobile: [' '].passwordInfo:this.fb.group({
    password: [' '].passwordConfirm: [' ']})});Copy the code

Angular form validator

  // Customize the validator
  xxx(param:AbstractControl):{[key:string]:any}{
    return null;
  }
  // eg:
  moblieValid(moblie:FormControl):any{
    ..........
    // return null; Indicates success
    // return {... }; You don't succeed
  }
  
  
  // Pre-define validators
  Validators.required ......
  nikname:["xxxx",[Validators.required,.....] ]... let niknameValid; boolean =this.formModel.get('nikname').valid;
  passwordInfo:this.fb.group({
      password: [' '].passwordConfirm: [' '] {},validator:this.passwordValidator}) // Verify multiple fields at once
    
Copy the code

Display error message

<div [hidden] =! "" formModel.hasError('required','nickname')"></div>
Copy the code

I’m going to start a new article on forms, HttpClient, etc. Thanks for your support.