簡體   English   中英

Angular 2 自己的類裝飾器來訪問依賴注入服務

[英]Angular 2 own Class Decorator to access Dependency Injection Service

我想創建一個類裝飾器TopicClass ,它向裝飾組件添加一個屬性和一個函數。 該函數必須訪問注入的服務。 我怎么做?

以下是嘗試失敗的內容:


@Component({
  selector: 'home',
  styleUrls: ['./home.component.css'],
  templateUrl: './home.component.html'
})
@TopicClass('home')
export class HomeComponent {
  constructor(private topicService: TopicService) { }
}

我無法通過插入的函數ngAfterViewInit訪問注入的 Service。


export function TopicClass(title: string) {
  return function (target: Function) {
    const original = target;

    function construct(constructor, args) {
      const c: any = function () {
        return constructor.apply(this, args);
      }
      c.prototype = constructor.prototype;

      const newInstance = new c();
      newInstance['topic'] = new Topic(title, '');

      newInstance['ngAfterViewInit'] = () => {
        newInstance['topicService'].setTopic(newInstance['topic']);
      }
      return newInstance;
    }

    const ctor: any = (...args) => {
      console.log("Service: " + original.prototype.topicService);
      return construct(original, args);
    };

    ctor.prototype = original.prototype;
    return ctor;
  }
}

問題是newInstance['topicService']未定義。

我已經建立了一個簡單的 Angular 項目進行測試: https : //github.com/ptea/angular-class-decorator-test

https://github.com/ptea/angular-class-decorator-test/blob/master/src/app/services/topic.service.ts

我還嘗試用一個簡單的 TypeScript 程序重現這個問題,它按預期工作:


newInstance['printStreet'] = () => {
  console.log(`printFirstnameStreet: ${newInstance['firstname']}, ${newInstance['street']}`);
}

https://github.com/ptea/angular-class-decorator-test/blob/master/dashboard.ts

這個問題的任何想法/解決方案?

TopicService未定義的原因是因為它從未被注入到組件中。 根據您當前的裝飾被重新定義的構造HomeComponent是沒有參數的構造函數。 這弄亂了 Angular 的 DI,因此在實例化組件時不會注入TopicService

我能想到的來完成你想要什么,最好的辦法是不能修改的構造HomeComponent ,轉而進軍ngOnInit方法來代替。 ngOnInit 方法是一個理想的候選方法,因為它在每個組件的生命周期中被調用一次,並且它有固定數量的參數,0,這使得它很容易包裝在另一個函數中。 您可以與ngAfterViewInit函數類似地執行此操作,以便在需要時使用該服務。

以下是如何修改TopicClassDecorator以實現您想要的結果:

export function TopicClass(title: string) {
  return function (target: Function) {

    let targetNgOnInit = target.prototype.ngOnInit;
    target.prototype.ngOnInit = function (){
      this.topic = new Topic(title, 'subTitle');

      if(targetNgOnInit){
        targetNgOnInit.apply(target);
      }
    }

    let targetNgAfterViewInit = target.prototype.ngAfterViewInit;        
    target.prototype.ngAfterViewInit = function (){
      this.topicService.setTopic(this.topic);

      if(targetNgAfterViewInit){
        targetNgAfterViewInit.apply(target);
      }
    }

    return target;
  }
}

一切協同工作的演示 Plunkr

我終於在不覆蓋 ngOnInit 函數的情況下采用了以下解決方案:


export function TopicClass(title: string) {
  return function (target: Function) {
    target.prototype.topic = new Topic(title);

    let targetNgAfterViewInit = target.prototype.ngAfterViewInit;        
    target.prototype.ngAfterViewInit = function () {
      this.topicService.setTopic(this.topic);

      if(targetNgAfterViewInit){
        targetNgAfterViewInit.apply(target);
      }
    }
  }
}

暫無
暫無

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

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