[英]Angular 2: Accessing injected dependencies from decorator
我正在制作一個可重復使用的Angular2組件,我希望用戶能夠指定一個模板字符串或templateUrl,然后該組件將通過屬性或通過某種服務方法設置該組件。
// 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();
}
// ...
};
}
@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動態創建組件
這很快就會變得毛茸茸,非常先進。 您基本上調用基於傳遞的參數加載組件。 這將允許您定義模板值,然后傳遞它以創建新組件。
這里有人用它來動態加載組件100% (超級hacky,與asyncRouter混淆)
優點:解決這個問題的“角度”方式,超級靈活。 缺點:如果你只需要一個簡單的開關,那就非常有用了 沒有多少人這樣做,所以幫助不會那么容易。
3.作弊(走出Angular之外)畢竟只是javascript。 您可以創建一個類或對象,粘貼在window
並調用自封裝函數
template: (function() {
return "<supertemplate-" + window.superTempId + "' />";
}())
(免責聲明)我沒有測試過這個,但似乎它會起作用
唯一的事情是什么時候。 這就是為什么你不能做其他服務,因為它們在完成元數據時不存在,但是如果你先設置模板或其他什么我不明白為什么它不起作用
優點:可以毫無困難地工作缺點:非常不是“角度方式”。 超級哈克。
這是一個相當常見的請求,所以我假設我們將通過“首選方法”或更多標准功能看到更多內容。
希望有所幫助!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.