Angular 2:从装饰器访问注入的依赖项

Mic*_*ley 5 angular

我正在制作一个可重复使用的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();
    }
    // ...
  };

}
Run Code Online (Sandbox Code Playgroud)

如何在Angular2中实现这一目标?

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

  constructor(private myService: MyService) {}

}
Run Code Online (Sandbox Code Playgroud)

虽然我的问题特别涉及如何实现动态模板,但更广泛的问题是是否可以从各种装饰器访问注入的依赖项实例.

Mic*_*ley 3

所以我终于找到了一种方法来使用自定义模板来完成我想要的事情。

我认为实际问题的答案一定是否定的,可注入在装饰器中不可用。这是我对 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>
Run Code Online (Sandbox Code Playgroud)

然后像这样使用 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());
}
Run Code Online (Sandbox Code Playgroud)

有关其工作方式和原因的演练,请参阅我就该主题撰写的这篇博客文章