Angular 4 筆記

STEP:

Prerequist:

(1) NodeJS: download the latest version

(2) npm:?

[sudo] npm install -g npm

(3) CLI:?

[sudo] npm uninstall -g angular-cli @angular/cli

npm cache clean

[sudo] npm install -g @angular/cli


1. install the angular CLI tool

npm install -g @angular/cli

2. clean up and create a new project

ng new <project_name>

3. install bootstrap in this project

npm install --save bootstrap

.angular-cli.json

"styles" : [

? ? ? ? "../node_modules/bootstrap/dist/css/bootstrap.min.css"

? ? ? ? "styles.css"

]

4. http://localhost:4200

ng serve

如果這個(gè)port already in use:?

lost -i : 4200

kill -q <PID>

5. create a new component without create the test files

ng g c <component_name> --spec false

6. create a new sub component without create the test files

ng g c <folder_name>/<sub_folder_name> --spec false

會(huì)generate automatically a component of 3 files:

* _________.component.ts

* _________.component.html

* _________.component.css

它會(huì)自動(dòng)在app.module.ts里加這個(gè)component在@NgModule的declaration里。


Bindings

1.?

* Property Binding : [ ]

* Event Binding : ( )

* Two-way Binding : [( ?)]

2. Two-way Binding Example

server.component.ts

export class ServerComponent implements OnInit {

? ? ? ? ? ?ServerName = "initServerName";

}

server.component.html

<input type="text"

? ? ? ? ? ? class="form-control"

? ? ? ? ? ? [(ngModel)] = "serverName">

<p>{{ serverName }}</p>

FormsModule is Required for Two-way Binding!


Directives

1. output data conditionally

*ngIf

server.component.html

<p *ngIf="serverCreated; else noServer">......</p>

<ng-template #noServer>

? ? ? ? ?<p>No Server is created!</p>

</ng-template>

server.component.ts

export class ServerComponent implements OnInit {

? ? ? ? ? serverCreated = false;

? ? ? ? ? onCreateServer() {

? ? ? ? ? ? ? ? ? ? ?this.serverCreated = true;

? ? ? ? ? ?}

}


2. Outputting List by ngFor

*ngFor

server.component.html

<app-server ?*ngFor="let server of servers"></app-server>


3. Unlike structural directives, attribute directives don't add or remove elements, they only change the element they were placed on.

*ngIf --------- structural directive

*ngFor ------- Outputting List by ngFor

[ngStyle] ----- attribute directive


4. "[ ?]" wants to bind some properties to this element, this property's name happens to be "ngStyle".

[ngStyle]

server.component.html

<p ??[ngStyle] = "{backgroundColor: getColor() }"> ...... </p>

server.component.ts

getColor() {

? ? ? ?return this.serverStatus === "online" ? "green" : "red";

}

Attribute Directives VS Structural Directives

1. Attribute Directives

* Look like a normal HTML attribute (possibly with data binding or event binding)

* Only affect / change the element they are added to

2. Structural Directives

* Look like a normal HTML attribute but have a leading * (for desugaring)

* Affect a whole area in the DOM (elements get added / removed)

Example for Custom Attribute Directive

- src

? ? ?- app

? ? ? ? ? ? - basic-highlight

? ? ? ? ? ? ? ? ? ? ? ? ? - basic-highlight.directive.ts

? ? ?- app.component.css

? ? ?- app.component.html

? ? ?- app.component.ts

? ? ?- app.module.ts

1. app.component.ts

export class AppComponent {

? ? ? ? ?addNumbers = [1, 3, 5];

? ? ? ? ?evenNumbers = [2, 4];

? ? ? ? ?onlyOdd = false;

}

2. app.component.css

.container {

? ? ? ? ? margin-top : 30px;

}

.odd {

? ? ? ? ? color: red;

}

3. app.component.html

<ul ?class="list-group">

? ? ? ? <div ? *ngIf="onlyOdd">

? ? ? ? ? ? ? ? <li ? class="list-group-item"

? ? ? ? ? ? ? ? ? ? ? ?[ngClass] = "{odd: odd % 2 ! == 0}"

? ? ? ? ? ? ? ? ? ? ? ?[ngStyle] = "{background: odd % 2 !== 0? 'yellow' : 'transparent'}"

? ? ? ? ? ? ? ? ? ? ? ? *ngFor = "let odd of oddNumbers">

? ? ? ? ? ? ? ? ? ? ? {{ odd ?}} ? </li></div>

? ? ? ? ? <div *ngIf="!onlyOdd">

? ? ? ? ? ? ? ? ? <li ? class="list-group-item"

? ? ? ? ? ? ? ? ? ? ? ? ? ?[ngClass] = "{odd: even % 2 ! == 0}"

? ? ? ? ? ? ? ? ? ? ? ? ? ?[ngStyle] = "{background: even % 2 !== 0? 'yellow' : 'transparent'}"

? ? ? ? ? ? ? ? ? ? ? ? ? ?*ngFor = "let even of evenNumbers">

? ? ? ? ? ? ? ? ? ? ? ? ?{{ even }} ? ?</li></div>

<p ?appBasicHighlight>Style me with basic directive!</p>

- use "onlyOdd=false"? to make condition of *ngIf

- [ngClass] = "{odd: odd % 2 ! == 0}

* [ngClass] is for changing the attribute of .css file

* the 1st odd is the class attribute of .css file

* the 2nd odd comes from the *ngFor in the same HTML element

- <p?appBasicHighlight>

appBasicHighlight is an attribute directive like [ngStyle], [ngClass], but our custom attribute directive.

4. basic-highlighting.directive.ts

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

@Directive ({

? ? ? ? selector: '[appBasicHighLighting]'

})

export class BasicHighLightDirective implements OnInit {

? ? ? ? constructor (private elementRef : ElementRef) {}

? ? ? ? ngOnInit() {

? ? ? ? ? ? ? this.elementRef.nativeElement.style.backgroundColor = 'green';

? ? ? ? ?}

}

5. app.module.ts

import {BasicHighLightDirective} from './basic-highlight/basic-highlight.directive';

@NgModule ({

? ? ? ? ?declarations: [

? ? ? ? ? ? ? ? ? ?AppComponent,

? ? ? ? ? ? ? ? ? ?BasicHighLightDirective

? ? ? ? ?],

......


Better Example for Custom Attribute Directive ?------ Renderer

- src

? ? ? - app

? ? ? ? ? ? ?- basic-highlight

? ? ? ? ? ? ? ? ? ? ? ? ? - basic-highlight.directive.ts

? ? ? ? ? ? ?- better-highlight

? ? ? ? ? ? ? ? ? ? ? ? ? - better-highlight.directive.ts

? ? ? ?- app.component.css

? ? ? - app.component.html

? ? ? - app.component.ts

? ? ? - app.module.ts

6. better-highlight.directive.ts

import {Directive, RendererV2, OnInit, ElementRef} from '@angular/core';

@Directive ({

? ? ? ? ?selector: '[appBetterHighLight]'

})

export class BetterHighLightDirective implements OnInit {

? ? ? ? ?constructor (private elRef: ElementRef,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?private renderer: Renderer) {}

? ? ? ? ?ngOnInit() {

? ? ? ? ? ? ? ? ? ?this.renderer.setStyle( this.elRef.nativeElement,?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?'background-color', 'blue', false, false);

? ? ? ? ?}

}

-?this.renderer.setStyle( this.elRef.nativeElement,?'background-color', 'blue', false, false);

better way to manipulate DOM

Always use Renderer to manipulate DOM!


HostListener => to Listen to Host Events?

=> to react to any events?

(Host: the element where the attribute directive places)

import {Directive,RendererV2, OnInit, ElementRef} from '@angular/core';

@Directive({

? ? ? ? selector:'[appBetterHighLight]'

})

export class BetterHighLightDirective implements OnInit {

? ? ? ? ?constructor (private elRef: ElementRef,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? private renderer: Renderer) {}

? ? ? ? ngOnInit() {?}

? ? ? ?@HostListener('mouseenter') mouseover(eventDate: Event) {

? ? ? ? ? ? ? this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue', false, false);

? ? ? ? }

? ? ? ? @HostListener('mouseleave') mouseleave(eventDate: Event) {

? ? ? ? ? ? ? ? ?this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'transparent', false, false);

? ? ? ? }

}


* dynamic way to change the background color from transparent to blue when the mouse is over and back to transparent when the mouse is left.

* @HostListener takes events name as arguments (string). These events, names are supported by DOM site.


Communication between Components with @Output & @Input

Example 01:

show Recipe if 'recipe' is selected on the menu bar, otherwise show shopping list if 'shopping-list' is selected.

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@Output()

header.component -----------------------> app.component

header.component.html

<a ... (click)="onSelected('recipe')">Recipes</a>

header.component.ts

@Output() featureSelected = new EventEmitter<string>();

onSelected(feature: string) {

? ? ? ? ?this.featureSelected.emit(feature);

}

@Output() to let its parent component know this element.

app.component.html

<app-header ?(featureSelected) = "onNavigate($event)">

(featureSelected) is the event element get from its child component header.component.ts and ($event) is sent from header.component.ts (.emit).

app.component.ts

loadedFeature = 'recipe';

onNavigate(feature: string) {

? ? ? ? ?this.loadedFeature = feature;

}

app.component.html

<app-recipe ?*ngIf="loadedFeature === 'recipe'"></app-recipe>

<app-shopping-list ? *ngIf="loadedFeature === 'shopping-list'"></app-shopping-list>


Example 02:

recipe-list is composed with recipe-items. So use recipe-item to show each item of recipe-list.

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@Input()

recipe-list -----------------------> ?recipe-item

recipe-list.component.ts

recipes: Recipe[] = {

? ? ? ? ?new Recipe( ...... ),

? ? ? ? ?new Recipe( ...... )

}

recipe-list.component.html

<app-recipe-item

? ? ? ? ? ? ?*ngFor = "let recipeEl of recipes"

? ? ? ? ? ? ?[recipe] = "recipeEl">?

</app-recipe-item>

recipe-item.component.ts

@Input() ?recipe: Recipe;

recipe-item.component.html

{{ recipe.name }}

{{ recipe.description }}


Example 03:

select one item from the recipe list and show its details in recipe detail area.

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? @Output() ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??@Output()

recipe-item --------------->? recipe-list--------------->? recipes ----

@Input()

----------->? recipe-detail

recipe-item.component.html

<a ? ?href="#" ? (click)="onSelected()" ></a>

{{ recipe.name }} {{ ?recipe.description }}

recipe-item.component.ts

@Output recipeSelected = new EventEmitter<void>();

@Input recipe: Recipe;

onSelected() {

? ? ? ? ? this.recipeSelected.emit();

}

recipe-list.component.html

<app-recipe-item

? ? ? ? ? ? ?*ngFor="let recipeEl of recipes"

? ? ? ? ? ? ?[recipe] = "recipeEl"

? ? ? ? ? ? ?(recipeSelected) = "onRecipeSelected (recipeEl)">?

</app-recipe-item>

recipe-list.component.ts

@Output() recipeSelected = new EventEmitter<Recipe>();

onRecipeSelected (recipe: Recipe) {

? ? ? ? ?this.recipeWasSelected.emit (recipe);

}

recipes.component.html

<app-recipe-list?

(recipeWasSelected) = "selectedRecipe = $event"> </app-recipe-list>

<app-recipe-detail

*ngIf="selectedRecipe; else infoText"

[recipe] = "selectedRecipe"></app-recipe-detail>

<ng-template #infoText>

? ? ? ? ?<p>Please select a Recipe!</p>

</ng-template>

(#infoText ------ local reference)

([recipe] = "selectedRecipe" --------?property bind)

recipes.component.ts

selectedRecipe: Recipe;

recipe-detail.component.ts

@Input() ?recipe: Recipe;

recipe-detail.component.html

{{ recipe.name }}

{{ recipe.imagePath }}


@ViewChild for <input> Form Element

shopping-edit.component.html

<input #nameInput>

<input #amountInput>

<button (click)="onAddedItem()"> ?Add ? </button>

shopping-edit.component.ts

@ViewChild('nameInput') nameInputRef: ElementRef;

@ViewChild('amountInput') amountInputRef: ElementRef;

@Output() ingredientAdded = new EventEmitter<Ingredient>();

onAddItem() {

? ? ? ? ? const ingName = this.nameInputRef.nativeElementRef.value;

? ? ? ? ? const ingAmountRef = this.amountRef.nativeElementRef.value;

? ? ? ? ? const newIngredient = new Ingredient(ingName, ingAmout);

? ? ? ? ? this.ingredientAdded.emit(newIngredient);

}

shopping-list.component.html

<app-shopping-edit

? ? ? ? ? (ingredientAdded) = "onIngredientAdded($event)"> ......?

</app-shopping-edit>

shopping-list.component.ts

ingredients: Ingredient[] = [

? ? ? ? ? new Ingredient('Apple', 5),

? ? ? ? ? new Ingredient('Tomatos', 10)

];

onIngredientAdded(ingredient: Ingredient) {

? ? ? ? ? ? this.ingredients.push(ingredient);

}


Custom Attribute Directive?

Build and use a Dropdown Directive

Before:

for opening a dropdown button

recipe-detail.component.html

<div class="btn-group open> ?...... </div>

After:

use Attribute Directive (custom attribute)

{CLI}: ? ? ng g d ./shared/dropdown.directive.ts

dropdown.directive.ts

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

@Directive ({

? ? ? ? ?selector: '[appDropdown]'

})

export class DropdownDirective {

? ? ? ? ? @HostBinding('class.open') isOpen = false;

? ? ? ? ? @HostListener('click') toggleOpen() {

? ? ? ? ? ? ? ? ? ? ? ? ?this.isOpen = !this.isOpen;

? ? ? ? ? ? ?}

}

recipe-detail.component.html

<div class="btn-group appdropdown> ...... </div>

app.module.ts

@NgModule ({

? ? ? ? ?declarations: [

? ? ? ? ? ? ? ? ? DropdownDirective

? ? ? ? ?]

})

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容