npm install -g @angular/cli ng new my-app cd my-app ng serve --open ng analytics project off ng build my-app -c production
ng generate component heroes ng generate component heroes -t #short for inlineTemplate=true ng generate component heroes --inline-style ng generate class hero ng generate pipe ng generate directive highlight ng generate service hero ng generate module app-routing --flat --module=app
import { Component, OnInit } from '@angular/core';
class Hero { constructor( public id: number, public name: string) { } }
@Component({ selector: 'app-heros', // styleUrls: ['./app.component.css'] // templateUrl: './app.component.html', template: ` <h1>{{title}}</h1> <h2>My favorite hero is: {{myHero.name}}</h2> <p>Heroes:</p> <ul> <li *ngFor="let hero of heroes"> {{ hero.name }} </li> </ul> <p *ngIf="heroes.length > 3">There are many heroes!</p> ` }) export class HerosComponent implements OnInit {
title = 'Tour of Heroes'; heroes = [ new Hero(1, 'Windstorm'), new Hero(13, 'Bombasto'), new Hero(15, 'Magneta'), new Hero(20, 'Tornado') ]; myHero = this.heroes[0];
<input (keyup)="onKey($event)"> <p>{{values}}</p> export class KeyUpComponent { values = ''; onKey(event: KeyboardEvent) { this.values += (event.target as HTMLInputElement).value + ' | '; } } 缺点:包含全部 DOM event 信息的$event整个传入component method, 不符合关注点分离原则 最佳实践:pass values, not element
##### get user input from a template reference variable ##### this won't work at all unless you bind to an event ##### (keyup)="0" the shortest template statement possible <input #box (keyup)="0"> <p>{{box.value}}</p>
detecting pure changes to primitives and object references
By default, pipes are defined as pure so that Angular executes the pipe only when it detects a pure change to the input value. A pure change is either a change to a primitive input value (such as String, Number, Boolean, or Symbol), or a changed object reference (such as Date, Array, Function, or Object).
transform(url: string): any { if (url !== this.cachedUrl) { this.cachedData = null; this.cachedUrl = url; this.http.get(url).subscribe(result =>this.cachedData = result); }
returnthis.cachedData; } }
<div *ngFor="let hero of ('assets/heroes.json' | fetch) "> {{hero.name}} </div> <p>Heroes as JSON: {{'assets/heroes.json' | fetch | json}} </p>`
Component lifecycle hooks
Hook
Purpose
Timing
ngOnChanges()
Respond when Angular sets or resets data-bound input properties. The method receives a SimpleChanges object of current and previous property values. Note that this happens very frequently, so any operation you perform here impacts performance significantly.
Called before ngOnInit() and whenever one or more data-bound input properties change.
ngOnInit()
Initialize the directive or component after Angular first displays the data-bound properties and sets the directive or component’s input properties.
Called once, after the first ngOnChanges().
ngDoCheck()
Detect and act upon changes that Angular can’t or won’t detect on its own.
Called immediately after ngOnChanges() on every change detection run, and immediately after ngOnInit() on the first run.
ngAfterContentInit()
Respond after Angular projects external content into the component’s view, or into the view that a directive is in.
Called once after the first ngDoCheck().
ngAfterContentChecked()
Respond after Angular checks the content projected into the directive or component.
Called after ngAfterContentInit() and every subsequent ngDoCheck().
ngAfterViewInit()
Respond after Angular initializes the component’s views and child views, or the view that contains the directive.
Called once after the first ngAfterContentChecked().
ngAfterViewChecked()
Respond after Angular checks the component’s views and child views, or the view that contains the directive.
Called after the ngAfterViewInit() and every subsequent ngAfterContentChecked().
ngOnDestroy()
Cleanup just before Angular destroys the directive or component. Unsubscribe Observables and detach event handlers to avoid memory leaks.
Called immediately before Angular destroys the directive or component.
Initializing a component or directive
Use the ngOnInit() method to perform the following initialization tasks.
Perform complex initializations outside of the constructor. Components should be cheap and safe to construct. You should not, for example, fetch data in a component constructor.
Set up the component after Angular sets the input properties. Constructors should do no more than set the initial local variables to simple values.
Cleaning up on instance destruction
Put cleanup logic in ngOnDestroy(), the logic that must run before Angular destroys the directive.
Unsubscribe from Observables and DOM events.
Stop interval timers.
Unregister all callbacks that the directive registered with global or application services.
notify another part of the application that the component is going away.
ngAfterViewInit() { // Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ... // but wait a tick first to avoid one-time devMode // unidirectional-data-flow-violation error // Angular's unidirectional data flow rule prevents updating the parent view's in the same cycle. setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0); }
# The :host selector is the only way to target the host element. You can't reach the host element from inside the component with other selectors because it's not part of the component's own template. The host element is in a parent component's template. :host { display: block; border: 1px solid black; }
The distinction between an HTML attribute and a DOM property is key to understanding how Angular binding works. Attributes are defined by HTML. Properties are accessed from DOM (Document Object Model) nodes.
A few HTML attributes have 1:1 mapping to properties; for example, id.
Some HTML attributes don’t have corresponding properties; for example, aria-*.
Some DOM properties don’t have corresponding attributes; for example, textContent.
Template binding works with properties and events, not attributes.
Attributes initialize DOM properties and then they are done. Property values can change; attribute values can’t. There is one exception to this rule. Attributes can be changed by setAttribute(), which re-initializes corresponding DOM properties.
Interpolation is a convenient alternative to property binding in many cases. When rendering data values as strings, there is no technical reason to prefer one form to the other, though readability tends to favor interpolation. However, when setting an element property to a non-string data value, you must use property binding.
Event binding
1 2 3
# without ngModel <input [value]="currentItem.name" (input)="currentItem.name=$event.target.value" >
1 2 3 4 5 6
// This component makes a request but it can't actually delete a hero. @Output() deleteRequest = new EventEmitter<Item>();
delete() { this.deleteRequest.emit(this.item); }
Two-way binding [(…)]
The [()] syntax is easy to demonstrate when the element has a settable property called x and a corresponding event named xChange.
# equal to <app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
Template reference variable
Angular assigns each template reference variable a value based on where you declare the variable:
If you declare the variable on a component, the variable refers to the component instance.
If you declare the variable on a standard HTML tag, the variable refers to the element.
If you declare the variable on an <ng-template> element, the variable refers to a TemplateRef instance, which represents the template.
If the variable specifies a name on the right-hand side, such as #var="ngModel", the variable refers to the directive or component on the element with a matching exportAs name.
1 2 3 4 5 6 7 8 9 10
<input #phone placeholder="phone number" />
<!-- lots of other elements -->
<!-- phone refers to the input element; pass its `value` to an event handler --> <button (click)="callPhone(phone.value)">Call</button>
# alternative syntax <input ref-fax placeholder="fax number" /> <button (click)="callFax(fax.value)">Fax</button>
@Component({ selector: 'app-svg', template: ` <svg> <g> <rect x="0" y="0" width="100" height="100" [attr.fill]="fillColor" (click)="changeColor()" /> <text x="120" y="50">click the rectangle to change the fill color</text> </g> </svg> `, styleUrls: ['./svg.component.css'] }) export class SvgComponent { fillColor = 'rgb(255, 0, 0)';
changeColor() { const r = Math.floor(Math.random() * 256); const g = Math.floor(Math.random() * 256); const b = Math.floor(Math.random() * 256); this.fillColor = `rgb(${r}, ${g}, ${b})`; } }
Directives
Built-in directives
Attribute directives
NgClass
NgStyle
NgModel
NgSwitch
…
structural directives
NgIf
NgFor
NgSwitchCase
NgSwitchDefault
…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<!-- toggle the "special" class on/off with a property --> <div [ngClass]="isSpecial ? 'special' : ''">This div is special</div>
currentStyles: {}; /* . . . */ setCurrentStyles() { // CSS styles: set per current state of component properties this.currentStyles = { 'font-style': this.canSave ? 'italic' : 'normal', 'font-weight': !this.isUnchanged ? 'bold' : 'normal', 'font-size': this.isSpecial ? '24px' : '12px' }; } <div [ngStyle]="currentStyles"> This div is initially italic, normal weight, and extra large (24px). </div>
1 2 3 4 5 6
# ngModel only works for element supported by a ControlValueAccessor <input [(ngModel)]="currentItem.name" id="example-ngModel">