接續 Angular 2 Module ( 1 )

Feature Module

Angular 一定會有一個 root module,但你也可以有 feature module,接著就來看看怎麼建立吧!
接續上一篇,假設我們依舊有CreditCardMaskPipeCreditCardServiceCreditCardComponent,但我們不想要直接放進 root module,我們想要再建立一個 module 來包裝這些東西,這時候新的 module 就是 feature module 了。

首先我們先創一個新的資料夾給新的 module

├── app
│   ├── app.component.ts
│   └── app.module.ts
├── credit-card
│   ├── credit-card-mask.pipe.ts
│   ├── credit-card.component.ts
│   ├── credit-card.module.ts
│   └── credit-card.service.ts
├── index.html
└── main.ts

現在有兩個資料夾裝有 module 了:app.module.tscredit-card.module.ts

先看看後者

//credit-card/credit-card.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { CreditCardMaskPipe } from './credit-card-mask.pipe';
import { CreditCardService } from './credit-card.service';
import { CreditCardComponent } from './credit-card.component';

@NgModule({
imports: [CommonModule],
declarations: [
CreditCardMaskPipe,
CreditCardComponent
],
providers: [CreditCardService],
exports: [CreditCardComponent]
})
export class CreditCardModule {}

我們已經知道這個是一個 feature module,但看一下內容其實跟 root module 長得很像,但仍然有幾點不同:

  • 引入 CommonModule 而非 BrowserModule
  • @NgModule 裡面多了 exportdeclarations 宣告用到的物件是 private,為了讓我們的 module 在被其他 module 使用的時候也可以動用自己模組裡的物件,export 可以讓 CeditCardComponent 變成 public, up 因為 AppComponent 之後會用到。但是 CreditCardMaskPipe 則繼續保持 private,因為這只有在自己模組中的溝通才會用到。

接著來看看 AppModule 如何使用 CreditCardModule

app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { CreditCardModule } from '…/credit-card/credit-card.module';
import { AppComponent } from './app.component';

@NgModule({
imports: [
BrowserModule,
CreditCardModule
],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }

imports 中引入要使用的其他模組

剛剛已經說 CeditCardComponent 被模組公開了,所以 AppComponent 這邊就可以拿來使用囉

//app/app.component.ts


@Component({

template: ... <app-credit-card></app-credit-card>
})
export class AppComponent {}

指令衝突

因為我們不再直接定義每個 component 他們所需要的 component 和 directive。所以我們需要知道 Angular Module 如何處理指令和組件同時作用在同一個元件上時候的衝突。也就是都針對同一個 selector 時候會怎麼做。

現在假設有兩個指令,針對同一個元件作用。

使背景變藍,字變灰

//blue-highlight.directive.ts
import { Directive, ElementRef, Renderer } from '@angular/core';

@Directive({
selector: '[appHighlight]'
})
export class BlueHighlightDirective {
constructor(renderer: Renderer, el: ElementRef) {
renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'blue');
renderer.setElementStyle(el.nativeElement, 'color', 'gray');
}
}

背景變黃

//yellow-highlight.directive.ts
import { Directive, ElementRef, Renderer } from '@angular/core';

@Directive({
selector: '[appHighlight]'
})
export class YellowHighlightDirective {
constructor(renderer: Renderer, el: ElementRef) {
renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
}
}

一個要讓背景變黃,一個要讓背景變藍,這時候會怎樣?

AppModule 這樣定義

//app.module.ts

// Imports

@NgModule({
imports: [BrowserModule],
declarations: [
AppComponent,
BlueHighlightDirective,
YellowHighlightDirective
],
bootstrap: [AppComponent]
})
export class AppModule { }

我們的組件長這樣,其中的 appHighlight 就是被兩個指令同時作用的東西。

//app.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'app-root',
template: '<h1 appHighlight>My Angular 2 App</h1>'
})
export class AppComponent {}

所以最後結論是如何?

答案是字是灰色,背景是黃色 (Plurk)

還記得剛剛的 module 嗎?

declarations: [
  ...,
  BlueHighlightDirective,
  YellowHighlightDirective
]

BlueHighlightDirective 先被執行, YellowHighlightDirective 再被執行,所以背景先變藍色後來又變成黃色。

結論就是當衝突發生時,當許多指令作用在同一個元件時,會依照順序執行。