簡體   English   中英

Angular 2:從裝飾器訪問注入的依賴項

[英]Angular 2: Accessing injected dependencies from decorator

我正在制作一個可重復使用的Angular2組件,我希望用戶能夠指定一個模板字符串或templateUrl,然后該組件將通過屬性或通過某種服務方法設置該組件。

在Angular 1中,這很簡單,我們可以這樣做:

// somewhere else in app
myService.setTemplateUrl('path/to/template.html');

// directive definition
function myDirective(myService) {

  return {
    template: function(element, attrs) {
      return attrs.templateUrl || myService.getTemplateUrl();
    }
    // ...
  };

}

如何在Angular2中實現這一目標?

@Component({
  selector: 'my-component',
  template: '...' // cannot see `mySerivce` from here, nor access the element attributes
})
export class MyComponent {

  constructor(private myService: MyService) {}

}

雖然我的問題特別涉及如何實現動態模板,但更廣泛的問題是是否可以從各種裝飾器訪問注入的依賴項實例。

所以我終於想出了一種方法來使用自定義模板做我想做的事情。

我認為實際問題的答案必須是否定的,注射器在裝飾器中不可用 這是我對Angular 2組件生命周期的理解。

對於那些感興趣的人,以下是我提出的用於實現用戶定義的自定義模板的內容:

給定一個指令SimpleTimer ,我們可以提供這樣的自定義模板:

<!-- app.ts template -->
<div *simpleTimer="#timer=timerApi">
  <div class="time">{{ timer.getTime() }}</div>
  <div class="controls">
    <button (click)="timer.toggle()">Toggle</button>
    <button (click)="timer.reset()">Reset</button>
  </div>
</div>

然后使用如下的TemplateRef和ViewContainerRef注射劑:

// SimpleTimer.ts
constructor(private templateRef: TemplateRef,
          private viewContainer: ViewContainerRef,
          private cdr: ChangeDetectorRef) {}

ngOnInit() {
  // we need to detach the change detector initially, to prevent a
  // "changed after checked" error.
  this.cdr.detach();
}

ngAfterViewInit() {
  let view = this.viewContainer.createEmbeddedView(this.templateRef);
  let api = {
    toggle: () => this.toggle(),
    reset: () => this.reset(),
    getTime: () => this.getTime()
  }
  view.setLocal('timerApi', api);

  setTimeout(() => this.cdr.reattach());
}

有關其工作原理和原因的演練, 請參閱我撰寫的關於該主題的博客文章

編輯:我剛剛注意到你的意圖是訪問DI。 截至目前你不能因為他們開火得太晚了。 這個答案的其余部分是做你詢問的模板。

我對這個問題非常感興趣,所以我花了比我想象的更多的時間來研究這個問題。 從目前我所知道的,沒有一種簡單的方法可以做到這一點。

您有3個主要選擇:

1.使用已知組件的* ng-if

這是迄今為止解決這個問題最簡單的方法。 只有幾個選項,您只能加載所需的組件

<special *ngIf="!type">Default</special>
<special *ngIf="type == 'awesome'"> I'm Awesome </special>
<special *ngIf="type == 'admin'">Admin Only</special>

優點:簡單,模板語法。 缺點:必須知道類型,當很多選項時會很煩人

2.使用DynamicComponentLoader動態創建組件

這很快就會變得毛茸茸,非常先進。 您基本上調用基於傳遞的參數加載組件。 這將允許您定義模板值,然后傳遞它以創建新組件。

這是一篇很好的文章,可以學習如何開始使用它

這是一個使用這種確切方法的SO答案

這里有人用它來動態加載組件100% (超級hacky,與asyncRouter混淆)

優點:解決這個問題的“角度”方式,超級靈活。 缺點:如果你只需要一個簡單的開關,那就非常有用了 沒有多少人這樣做,所以幫助不會那么容易。

3.作弊(走出Angular之外)畢竟只是javascript。 您可以創建一個類或對象,粘貼在window並調用自封裝函數

template: (function() {
    return "<supertemplate-" + window.superTempId + "' />";
}())

(免責聲明)我沒有測試過這個,但似乎它會起作用

唯一的事情是什么時候。 這就是為什么你不能做其他服務,因為它們在完成元數據時不存在,但是如果你先設置模板或其他什么我不明白為什么它不起作用

優點:可以毫無困難地工作缺點:非常不是“角度方式”。 超級哈克。

這是一個相當常見的請求,所以我假設我們將通過“首選方法”或更多標准功能看到更多內容。

希望有所幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM