Angular 4指令显示@input值未定义

时间:2017-12-03 11:25:23

标签: angular typescript directive angular2-directives

我是使用angular指令的新手,所以我创建了一个指令如下:

import { Directive, ElementRef, Input, Output } from '@angular/core';

@Directive({
  selector: "[bonusCard]"
})
export class BonusCard {
  @Input() bonus: string;
  @Input() amount: string;
  @Input() isSeleted: string;
  constructor(private el: ElementRef){
    el.nativeElement.innerHTML = this.getTemplate()
  }

  getTemplate(){
    return ''+
      '<div>'+
        '<div class="bonus">'+this.bonus+'</div>'+
        '<div class="amount">'+this.amount+'</div>'+
        '<div class="radio '+(this.isSeleted?'is_seleted':'')+'"></div>'+
      '</div>' +
      '';
  }
}

我在模板中使用此指令如下:

  <div class="column col-3" *ngFor="let b of bonusJson;let i = index" bonusCard [bonus]="b.bonus" [amount]="b.amount" [isSeleted]="i==activeBonus"></div>

其中变量定义如下:

bonusJson = [{
    bonus:1500,
    amount:2000
  },{
    bonus:1000,
    amount:1000
  },{
    bonus:500,
    amount:500
  },{
    bonus:0,
    amount:100
  }];
  activeBonus = 0;

但是视图无法正确呈现,它在视图中显示undefind,如下所示。

$ enter image description here

1 个答案:

答案 0 :(得分:5)

TL; DR

不要在构造函数中使用@Input()属性的值。请改用ngOninit()

答案很长

您正在构造函数中执行代码,但是构造函数Input绑定之前执行。

当您引导应用程序时,Angular将使用new keywoard为每个组件创建一个组件树,从而执行它们的构造函数。但是在此阶段更改检测周期尚未激活,树尚未附加到 DOM ,并且大多数应用程序数据尚未被提取和解析

构造函数不是放置复杂初始化逻辑的理想位置,正如您可以在Angular团队的开发人员编写的this guide中读到的那样。您在构造函数中需要做的只是基本的初始化和依赖注入结果。

ngOnInit() hook方法中的事情发生了变化。当Angular调用此方法时,它已经将每个组件附加到DOM,注入了所有必需的依赖项和已处理的输入绑定。您可以放心地使用Input()财产。

具体答案

回到你的问题,你打电话getTemplate()它会查找this.bonusthis.amountthis.isSelected,但仍然无法解析父组件的视图输入的proprierite仍未绑定,因此您会收到undefined

要避免此问题,请将代码从构造函数移至 ngOnInit 挂钩。

export class BonusCard implements OnInit {
  @Input() bonus: string;
  @Input() amount: string;
  @Input() isSeleted: string;

  constructor(private el: ElementRef) {}

  ngOnInit() {
    this.el.nativeElement.innerHTML = this.getTemplate()
  }

三个最后的笔记

我想提供三个额外的建议来改进您的代码:

  • 使用DomSanitizer绑定组件中的HTML ,您可以阅读更多here
  • 使用模板字符串,您可以使用它用引号替换引号(`),这样就可以在几行上编写模板
  • 如果您确定要比较同一类型的两个变量,则可以使用===代替==

所以:

[isSeleted]="i===activeBonus"

return `<div>
          <div class="bonus"> ${this.bonus} </div>
          <div class="amount"> ${this.amount} </div>
          <div class="radio ${this.isSeleted?'is_seleted':''}"></div>
        </div>`;