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

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

         ]

})

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容