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

Angular 4 directive is displaying undefined for @input values

我是 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,如下所示。

$

TL;DR

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


长答案

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

当您 bootstrap 您的应用程序时,Angular 将使用 new 关键字为每个组件创建一个组件树,然后执行它们的构造函数。但是在这个阶段 change detection 周期还没有激活,树还没有附加到 DOM 和大部分应用程序数据尚未被提取和解析。

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

ngOnInit() 挂钩方法发生了变化。相反,当 Angular 调用此方法时,它已经将每个组件附加到 DOM,注入了所有必需的依赖项并处理了输入绑定。您可以放心地使用您的 Input() 属性。


具体答案

回到你的问题,你调用 getTemplate() 它寻找 this.bonusthis.amountthis.isSelected 但父组件的视图仍然没有被解析并且输入属性仍未绑定,因此您收到的是 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>`;