1. Use the else

  • Syntactic sugar else
   <div *ngIf="isLoggedIn; else loggedOut">
   Welcome back, friend.
   </div>

   <ng-template #loggedOut>
   Please friend, login.
   </ng-template>
Copy the code
  • Code is equivalent to the following
<ng-template [ngIf]="isLoggedIn" [ngIfElse]="loggedOut">
 Welcome back, friend.
</ng-template>

<ng-template #loggedOut>
 Please friend, login.
</ng-template>
Copy the code
  • At a higher level:
<ng-container *ngIf="isLoggedIn; then loggedIn; loggedOut">
<ng-container>

<ng-template #loggedIn>
 Welcome back, friend.
</ng-template>

<ng-template #loggedOut>
 Please friend, login.
</ng-template>
Copy the code

2. Ng – show abandoned

<div [hidden]=! "" isLoggedIn">
 Welcome back, friend.
</div>
Copy the code

3. Use AngularJS components in Angular

  • Angularjs components
  export const heroDetail = {
  bindings: {
    hero: '<',
    deleted: '&'
  },
  template: `
    <h2>{{$ctrl.hero.name}} details! </h2> <div><label>id: </label>{{$ctrl.hero.id}}</div>
    <button ng-click="$ctrl.onDelete()">Delete</button>
  `,
  controller: function() { this.onDelete = () => { this.deleted(this.hero); }; }};Copy the code
  • Defining Angular directives
import { Directive, ElementRef, Injector, Input, Output, EventEmitter } from '@angular/core';
import { UpgradeComponent } from '@angular/upgrade/static';
import { Hero } from '.. /hero';

@Directive({
  selector: 'hero-detail'
})
export class HeroDetailDirective extends UpgradeComponent { 
 Requires data binding corresponding to the AngularJS component definition
  @Input() hero: Hero;
  @Output() deleted: EventEmitter<Hero>;

  constructor(elementRef: ElementRef, injector: Injector) {
    super('heroDetail', elementRef, injector); }}Copy the code
  • Use directives to reference AngularJS components
import { Component } from '@angular/core';
import { Hero } from '.. /hero';

@Component({
  selector: 'my-container',
  template: `
    <h1>Tour of Heroes</h1>
    <hero-detail [hero]="hero"
                 (deleted)="heroDeleted($event)">
    </hero-detail>
  `
})
export class ContainerComponent {
  hero = new Hero(1, 'Windstorm');
  heroDeleted(hero: Hero) {
    hero.name = 'Ex-'+ hero.name; }}Copy the code

4. Common template syntax

  • Structural instructions:

    • The list of rendering
    <li *ngFor="let hero of heroes;">
        {{ hero }}
    </li>
    Copy the code
    • List renders and displays serial numbers
      <li *ngFor="let hero of heroes; let i = index;">
         {{i+1}} {{ hero }}
     </li>
    Copy the code

    It is recommended to add trackBy to improve performance

     <li *ngFor="let hero of heroes; trackBy:trackByFn">
        {{ hero }}
    </li>
    trackByFn(index, item) {
     return item.id;
    }
    Copy the code
    • Conditions apply colours to a drawing
    <li *ngIf="isHidden">
        {{ hero }}
    </li>
    Copy the code
    • To choice
    <div [ngSwitch]="hero? .emotion">
      <app-happy-hero    *ngSwitchCase="'happy'"    [hero]="hero"></app-happy-hero>
      <app-sad-hero      *ngSwitchCase="'sad'"      [hero]="hero"></app-sad-hero>
      <app-confused-hero *ngSwitchCase="'confused'" [hero]="hero"></app-confused-hero>
      <app-unknown-hero  *ngSwitchDefault           [hero]="hero"></app-unknown-hero>
    </div>
    Copy the code
  • Attribute directives:

    • One-way data input
     Dynamic binding, update will trigger the corresponding child component
     <app-hero-detail [hero]="currentHero"></app-hero-detail>
     
     # Bind string, non-variable value
     <app-item-detail childItem="parentItem"></app-item-detail>
    Copy the code
    • Event feedback
     <w-button (click)="handlerClick" />
     
     Two-way data binding
     <input [(ngModel)]="currentItem.name">
    
     # equivalent
     <input [value]="currentItem.name"
        (input)="currentItem.name=$event.target.value" >
    Copy the code
    • Attribute to add
    <button [attr.aria-label]="help">help</button>
    
    <div [class.special]="isSpecial">Special</div>
    
    <button [style.color]="isSpecial ? 'red' : 'green'">
    
    <button [class]="{foo: true, bar: false}" />
    Copy the code
    • Custom bidirectional data binding -x and xChange
     import { Component, Input, Output, EventEmitter } from '@angular/core';
    
     @Component({
        selector: 'app-sizer',
        templateUrl: './sizer.component.html',
        styleUrls: ['./sizer.component.css']})export class SizerComponent {
    
    
     @Input()  size: number | string;
     @Output() sizeChange = new EventEmitter<number>();
    
     dec() { this.resize(-1); }
     inc() { this.resize(+1); } resize(delta: number) { this.size = Math.min(40, Math.max(8, +this.size + delta)); this.sizeChange.emit(this.size); }}# html
     <app-sizer [(size)]="fontSizePx"</app-sizer> is equivalent to <app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
    Copy the code

5.ng-template

    <div *ngIf="isLoggedIn">
    Welcome back, friend.
    </div>
    # equivalent
    <ng-template [ngIf]="isLoggedIn">
        Please friend, login.
    </ng-template>
Copy the code

6.ng-content

# html
	
  <fa-input icon="envelope">
     <i class="fa fa-envelope"></i>
     <input inputRef type="email" placeholder="Email">
  </fa-input>

# js component 
@Component({
  selector: 'fa-input',
  template: `
    <ng-content ></ng-content>  # match fa-input all other matches that are not specified
    <ng-content select="input"></ng-content> # Match the specific input tag in fa-input
  `})
export class FaInputComponent {
   ...
}
Copy the code

7. Inject singleton mode

  • The singleton pattern
import { Injectable } from '@angular/core';

Inject root Use webpack tree-shaking, optimize packaging
@Injectable({
    providedIn: 'root',})export class UserService {
}

Copy the code
  • Privoder configuration
@NgModule({
...
providers: [UserService],
...
})
Copy the code
  • If both are provided, be aware that reading memory data from UserService may not be possible!!

8. Angularjs UI – grid

  • Upgrade with technology -ag-grid
  • For the component upgrade solution, see Summary 3

Directive covers AngularJS UI-grid and is used in Angular. However, it is important to note that the configuration of the uI-grid file must not be modified. Otherwise, it will affect the existing UI display function.

For example, the new version does not require vertical scrolling. Manually changing the default AngularJS UI-Grid vertical scroll bar configuration will result in the existing AngularJS table not displaying vertical scroll bars and incomplete data display.

We should define configuration items in our Angular components, not in generic configuration changes
this.gridOptions = {
   enableFiltering: true,
   useExternalFiltering: true,
   columnDefs: [
     { name: 'name'.enableFiltering: false },
     { name: 'gender' },
     { name: 'company'.enableFiltering: false}].enableHorizontalScrollbar: 1, # 0 off, 1 on
   enableVerticalScrollbar:0 # 0 off, 1 on
}

Copy the code

Render2 update style, ViewChild selects DOM

#html 
<div #mydiv><input></div>

# js 
@ViewChild('mydiv') mydiv: ElementRef 
constructor( 
    private el:ElementRef,
    private renderer2: Renderer2){
}
ngOnInit(){
    this.renderer2.setStyle(this.el.nativeElement.querySelector('.btn1'),'background'.'green');
}

Render2 below is recommended to minimize the strong coupling between application and render layers
Copy the code
# render2 apiabstract data: {... } destroyNode: ((node: any) => void) | null abstract destroy(): void abstract createElement(name: string, namespace? : string): any abstract createComment(value: string): any abstract createText(value: string): any abstract appendChild(parent: any, newChild: any): void abstract insertBefore(parent: any, newChild: any, refChild: any): void abstract removeChild(parent: any, oldChild: any, isHostElement? : boolean): void abstract selectRootElement(selectorOrNode: any, preserveContent? : boolean): any abstract parentNode(node: any): any abstract nextSibling(node: any): any abstractsetAttribute(el: any, name: string, value: string, namespace? : string): void abstract removeAttribute(el: any, name: string, namespace? : string): void abstract addClass(el: any, name: string): void abstract removeClass(el: any, name: string): void abstractsetStyle(el: any, style: string, value: any, flags? : RendererStyleFlags2): void abstract removeStyle(el: any, style: string, flags? : RendererStyleFlags2): void abstractsetProperty(el: any, name: string, value: any): void
  abstract setValue(node: any, value: string): void
  abstract listen(target: any, eventName: string, callback: (event: any) => boolean | void): () => void
Copy the code

11. The class evaluates attributes

@Component({
  selector: 'fa-input',
  template: `
    <i class="fa" [ngClass]="classes"></i>
  `,
  styleUrls: ['./fa-input.component.css']})export class FaInputComponent {
  @Input() icon: string;
	
  get  classes() {
    const cssClasses = {
      fa: true
    };
    cssClasses['fa-' + this.icon] = true;
    returncssClasses; }}Copy the code

12. Element binding

  • @hostBinding () can add classes, styles, attributes, and so on to the directive’s host element,
  • @hostListener () can listen for events on host elements.
import { Directive, HostBinding, HostListener } from '@angular/core';

@Directive({
  selector: '[highLight]' # define directive
})
export class HighLightDirective{
  colors = [
    'hotpink'.'lightskyblue'.'goldenrod'.'peachpuff'
  ]; 
  @HostBinding('style.color') color: string;
  @HostBinding('style.borderColor') borderColor: string;  # define style
  @HostListener('keydown') onKeydown() {# define listenerconst color = Math.floor(Math.random() * this.colors.length); this.color = this.borderColor = this.colors[colorPick]; }}Copy the code

13.viewChild

  • ViewChild Selects a node within the component template, of type ElementRef or child
  • ContentChild Selects the child component referenced by the current component.
  • The difference is that the ViewChild selects the Shadow DOM and the ContentChild selects the Light DOM. Normally, the ViewChild is ok

14. Element width

  • element clientWidth

The clientWidth property value for inline elements and elements without CSS styles is 0. The element. clientWidth property represents the internal width of an Element, in pixels. This property includes padding, but not border border, margin, and vertical scroll bar (if any). When clientWidth is used on the root element (element) (or on, if the document is in quirks mode), the viewPort width is returned (without any scrollbars).

  • jquery width()

Always refer to content width, excluding border

15. SCSS is invalid

# SCSS document
input {
 border: none;
 outline: none;
}
# CSS interface runtime
input[_ngcontent-c0] {
 border: none;
 outline: none;
}
Add the compile processing
:host ::ng-deep input {
 border: none;
 outline: none;
}
Copy the code

16. Httpclient accepts json format by default

# back end pass text, need to set the type
this.http.get(this.configUrl,{responseType:'text'}) .subscribe((data: any) => this.config = { ... data });Copy the code
# sourceget(url: string, options? : { headers? : HttpHeaders | { [header: string]: string | string[]; };# default values are: the response | body | eventobserve? :'body';The body in response is read by defaultparams? : HttpParams | { [param: string]: string | string[]; }; reportProgress? : boolean;# default values are: arraybuffer | json | blob | textresponseType? :'json';The ts parameter type is optional. The default value is json.withCredentials? : boolean; }): Observable<Object>;Copy the code

17. Memory leak risk

Angular recommends RXJS for responsive development

import { from } from 'rxjs';

const data = fromEvent('click');
// Subscribe to begin listening for async result
this.$obser = data.subscribe({
  next(response) { console.log(response); },
  error(err) { console.error('Error: ' + err); },
  complete() { console.log('Completed'); }});Copy the code

The subscribe code above will subscribe multiple times without unsubscribe

We can optimize it in a number of ways

  • 1. Unsubscribe from OnDestroy
public ngOnDestory() {if( this.$obser){
         this.$obser.unsubscribe(); }}Copy the code
  • 2. Similar to the above, but refer to this code
# Use Subscription, one to cancel, all to cancel
import { interval } from 'rxjs';
 
const observable1 = interval(400);
const observable2 = interval(300);
 
 # subscription = new subscription (); // Global creation, then add in sequence
const subscription = observable1.subscribe(x => console.log('first: ' + x));
const childSubscription = observable2.subscribe(x => console.log('second: ' + x));
 
subscription.add(childSubscription);
 
setTimeout(() => {
  // Unsubscribes BOTH subscription and childSubscription
  subscription.unsubscribe();
}, 1000);
Copy the code
  • 3. Switch to asynchronous using RXJS Pipe
# Specific details also rely on RXJS operator proficiency, later collated a for your reference
@Component({
  selector: 'async-observable-pipe',
  template: `<div><code>observable|async</code>:
       Time: {{ time$ | async }}</div>`
})
export class AsyncObservablePipeComponent {
  time$ = new Observable<string>(observer => {
    setInterval(() => observer.next(new Date().toString()), 1000);
  });
}
Copy the code

18. Adjusted component update strategy to optimize component tree update performance

@Component({
    selector: 'app-product', template: `... `, changeDetection: ChangeDetectionStrategy.OnPush })export class ProductComponent { ... }
Copy the code

OnPush is triggered when

  • The @Input value has changed
  • Component, or child component, that fires Dom events
  • DetectChanges method call
  • The async Pipe changed. Procedure

19. The tooltip displaygetBoundingClientRect

# html
<div class="tips" #tooltip></div>

#ts
class ToolTipCompoment {
    @ViewChild('tips')
    tips: ElementRef;
    
    showTip(){ const dom = this.tips.nativeElement; const pos = dom.getBoundingClientRect(); . }}Copy the code

20 Observable lazy push

#rxjs 
import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  setTimeout(() => {
    subscriber.next(4);
    subscriber.complete();
  }, 1000);
});
Copy the code

Now that the code is defined, does that mean we can get the data? The answer is no, as described on the website:

To invoke the Observable and see these values, we need to subscribe to it:

The code needs to be modified as follows, add subscribe:

import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  setTimeout(() => {
    subscriber.next(4);
    subscriber.complete();
  }, 1000);
});

console.log('just before subscribe');
observable.subscribe({
  next(x) { console.log('got value ' + x); },
  error(err) { console.error('something wrong occurred: ' + err); },
  complete() { console.log('done'); }}); console.log('just after subscribe');
Copy the code

Similarly, we need Subscribe to call all operators of Rxjs to get the value

  • One way: Subscribe
  • Another way, HTML interface, (count $| async)

Angular HttpClient front-end log collection failed

# define HTTP API requests
getConfig() {
  return this.http.get(this.configUrl);
}

# we'll define it soon
showConfig() {
  this.configService.getConfig()
    .subscribe((data: Config) => this.config = {
        heroesUrl: data['heroesUrl'],
        textfile:  data['textfile']}); }Copy the code

Combined with 20, we can see that HTTP requests cannot be sent without subscribe.

Especially in the front-end logging, if only the definition, no subscribe, then the front-end logging is not successful record oh!!

22. Async has the same effect as SUBSCRIBE

20 If async loading is used to export data, such as JSON and CSV files, multiple files may be exported at a time.

The fundamental reason is that the effect of ASyn is the same as the effect of subscribe, multiple subscriptions, no unsubscribe, trigger multiple save

23. RXJS creates a distinction between data streams and asynchronies

Synchronous data stream

  • Create-observable constructor
  • Of – Enumerate limited
  • Range – a specific range
  • The generate – cycle
  • Repeat, repeat
  • The empty empty –
  • Never – never end
  • Throw – Throws an error

Asynchronous data flow

  • Interval – Specifies a specific interval
  • The timer timing –
  • from
  • fromEvent
  • ajax
  • defer

When writing code, asynchrony is often not thought of, resulting in undefined exception.

24. angular iframe loading

We expect the iframe resource to finish loading and the loading to end.

However, we found that Chrome and Safari Load trigger twice, while Firefox and IE11 trigger only once

# html
<div *ngIf="loading" class="v-loading"></div>
<iframe  [src]="url" (load)="load()">

# ts
class helperComponent extends onInit{
    loading = false;
    constructor(){
        console.log("this is contructor...");
        //this.loading = true; The general way to write this is, at construction time, initialize}ngOnInit(){
        console.log("this is init...");
        this.loading = true;
    }
    load(){
        console.log("this is load..."); }} / / output chrome | safari this is its constructor / / if the initialization heretrueChrome, Safari, loading this is load...# I'm going to call it one more time,
this is init...  # so, we put loding= true here
this is load...

ff | ie11
this is contructor
this is init... 
this is load...
Copy the code

25. Array sort

Do you have any idea what the result will be? Does an exception occur?
const arr = [1,undefined,2,undefined,4,undefined];
arr.sort((a,b) => {
   return a.name > b.name
});
Copy the code
#output 
[1, 2, 4, undefined, undefined, undefined]
Copy the code

Here’s why:

If compareFunction is supplied, all non-undefined array elements are sorted according to the return value of the compare function (all undefined elements are sorted to the end of the array, with no call to compareFunction)

26. NGRX undefined problem

NGRX is used for status management, similar to sessionStorage, with get/set

# selectors
export const userLogin = createSelector(
  getCounterValue,
  (counter, props) => counter * props.multiply
);

ngOnInit() {
  this.counter = this.store.pipe(select(fromRoot.getCount, { multiply: 2 }))
}

Copy the code

We pay in selector for two common reasons:

  • Corresponding action, no trigger, no set corresponding value
  • The corresponding value is set, but the get is not written correctly, for example
# Correct way to write
this.counter = this.store.pipe(select(fromRoot.getCount, { multiply: 2 }))

# False
  this.counter = this.store.pipe(fromRoot.getCount, { multiply: 2 })
Copy the code

27. Cannot find module ‘typescript’

TypeScript is required if you want to compile using ts-node.

npm install -D typescript
npm install -D ts-node
Copy the code

28. ngrx store pip sync or async ?

export const getList = () =>
  createSelector(
    (state, props) => state.counter[props.key]
);

console.log("before....");
this.store.pipe(
  select(fromRoot.getList(), { key: 'counter2'}),
  tap(() => {
    console.log("store...."); })); console.log("after....");


//output
before....
store....
after....

Copy the code

EMPTY and Of({})

EMPTY only fires complete, not Next. Caution is required when integrating NGRX.

Of, next trigger first, execute complete

import { fromEvent, interval , of, EMPTY } from 'rxjs';
import { switchAll, map, tap } from 'rxjs/operators';
 
EMPTY.subscribe(
  () => {
    console.log('empty next');
  },
  () => {
    console.log('empty error');
  },
  () => {
    console.log('empty complete');
  }
)

of({}).subscribe(
  () => {
    console.log('of next');
  },
  () => {
    console.log('of error');
  },
  () => {
    console.log('of complete');
  }
)

//output
empty complete
of next
of complete
Copy the code

Write Angular Export with RXJS

Even if data flow listening is turned off

getData: () => {
    const data1:Observabl<any> = this.getDataone();
    const data2:Observable<any> = this.getDataTwo();
    returnCombineLatest ([data1,data2]). Pipe (map([data1,data2]) => {// Data integration, return JSON STRreturnJsonStr}) // If the data1 / data2 changes, the download will be triggered. Even if you don't click the download button take (1),} this. ExportService. GetData (). The pipe ((res) = > {/ / download js logic}). The subscribe ()Copy the code

More recommended

Angular8 HttpClient 30 minutes in depth

Angular Render2?

20 Angular Open Source Projects you should know about

Angular7/8 2 ways to read local json

Angular8 UI-Grid alternative Ag-Grid getting started

Learn more about instructions

reference

  • angular ng-template
  • angular ng-content
  • The binding element
  • element clientWidth
  • Presents website