iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 13
0
Modern Web

從巨人的 Tip 看 Angular系列 第 13

[Day 13] exportAs,透過 template variable 取得 directive 實體

  • 分享至 

  • xImage
  •  

Attribute directive 可以改變 element 本身的行為、也可以為 element 擴展新的能力。但有時候我們可能會需要在 component 內直接與 directive 的實體互動,藉以達成更多效果。


在 Angular 內要取得 directive 的方法,就是透過 @Directive decorator 內的 exportAs 這個屬性,來讓 Angular 可以在 template variable 辨識出這個變數指向的是 directive 而非 element 本身。

關於範例

// HTML
<p>app works!</p>
<button (click)="clickMe()">Click me to add new item!</button>
<ol appMydir #tMydir='mydir'>
</ol>

// TypeScript
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  @ViewChild('tMydir') mydir: MydirDirective;
  title = 'day12';
  clickMe(): void {
    this.mydir.add();
  }
}

↑ Block 1:AppComponent

@Directive({
  selector: '[appMydir]',
  exportAs: 'mydir'
})
export class MydirDirective implements OnChanges {
  count = 1;
  constructor(private ele: ElementRef<HTMLDivElement>) {}

  add(): void {
    const litem = document.createElement('li');
    litem.textContent = `item ${++this.count}`;
    this.ele.nativeElement.appendChild(litem);
  }
}

↑ Block 2:MydirDirective

範例的程式碼很單純,我在 MydirDirective 的 @Directive decorator 新增了一個 exportAs 屬性,並在 AppComponent 的 ol element 使用這個 directive,同時新增一個 template variable:#tMydir,並指派 mydir。最後就可以在 AppComponent 內透過 @ViewChild('tMydir') 的方式來取得 MydirDirective 的實體,並使用這個 directive 的方法來新增 li element。

01.gif

↑ Image 1:範例結果

以上就是今天要介紹的 Tip!只要在 @Directive 加入 exportAs 的屬性,就可以搭配 template variables 以及 @ViewChild 的方式來取得 directive 的實體囉!


以下是針對 Angular 怎麼處理 template variables 的過程,有興趣的讀者歡迎繼續閱讀!

Angular 如何處理 template variables

const _c0 = ["tMydir"];
class AppComponent {
  // ... 略
}
AppComponent.ɵcmp = _angular_core__WEBPACK_IMPORTED_MODULE_0__[
  "ɵɵdefineComponent"
]({
  type: AppComponent,
  selectors: [["app-root"]],
  viewQuery: function AppComponent_Query(rf, ctx) {
    // ... 略
  },
  decls: 6,
  vars: 0,
  consts: [
    [3, "click"],
    ["appMydir", ""],
    ["tMydir", "mydir"],
  ],
  template: function AppComponent_Template(rf, ctx) {
    if (rf & 1) {
      // ... 略
      _angular_core__WEBPACK_IMPORTED_MODULE_0__["ɵɵelement"](4, "ol", 1, 2);
    }
  },
  directives: [_mydir_directive__WEBPACK_IMPORTED_MODULE_1__["MydirDirective"]],
  styles: [
    // ... 略
  ],
});

↑ Block 3:AppComponent 經過 compile 的結果

ɵɵelement 函式的傳入參數,分別是 indexnameattrsIndex 以及今天能夠處理 template variable 的關鍵:localRefsIndex

以本例來說,ol 這個 element 身上帶著 appMydir 這個 attribute directive 所以它的 attrsIndex 會是:1,同時它也身上帶著 #tMydir 這個 template variable,所以它的 localRefsIndex 是:2。

當 Angular 在 render 這個 component 的時候,就會按照以下的順序來處理 template variables:

  1. ɵɵelement
  2. ɵɵelementStart
    1. elementStartFirstCreatePass
      1. resolveDirectives

最終就是由 resolveDirectives 來處理與 directive 有關的事情了。

至於 Angular 怎麼透過 @ViewChild 來找出 template variable 所對應的 element 或是 directive 的實體,就又是另一篇文章了。

快一半啦 ?

以下按照入團順序列出我們團隊夥伴的系列文章!


上一篇
[Day 12] 深度探討 Angular 解析 Attribute directive 的背後流程
下一篇
[Day 14] * 與 microsyntax
系列文
從巨人的 Tip 看 Angular30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言