Angular 4 笔记

作者: 于恺雯 | 来源:发表于2017-06-12 08:00 被阅读0次

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

如果这个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

会generate automatically a component of 3 files:

* _________.component.ts

* _________.component.html

* _________.component.css

它会自动在app.module.ts里加这个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

         ]

})

相关文章

网友评论

    本文标题:Angular 4 笔记

    本文链接:https://www.haomeiwen.com/subject/jnukqxtx.html