Angular 2: 组件交互,可选输入参数

74

我有一个实现,父组件想通过在子组件中使用的 @Input 参数向子组件传递某些数据。然而,这种数据传输是可选的,根据需求,父组件可能会或者不会传递它。组件中是否可以有可选的输入参数?我在下面描述了一个场景:

 <parent>
    <child [showName]="true"></child> //passing parameter
    <child></child> //not willing to passing any parameter
</parent>



//child component definition
@Component {
    selector:'app-child',
    template:`<h1>Hi Children!</h1>
          <span *ngIf="showName">Alex!</span>`
}


export class child {

    @Input showName: boolean;

    constructor() { }

}

3
可以有可选输入,检查ngAfterViewInit生命周期事件是否已初始化输入。 - galvan
谢谢 @galvan,它起作用了! - Sumit Agarwal
3个回答

137

您可以按以下方式使用 ( ? ) 运算符

import {Component,Input} from '@angular/core';
@Component({
    selector:'child',
    template:`<h1>Hi Children!</h1>
          <span *ngIf="showName">Alex!</span>`
})


export class ChildComponent {

    @Input() showName?: boolean;

    constructor() { }

}

使用子组件的父组件将如下所示

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
      <child [showName]="true"></child>
      <child ></child>
    </div>
  `,
})
export class App {
  name:string;
  constructor() {
    this.name = 'Angular2'
  }
}

在线演示


12
这应该是答案。同时,使用默认值 @Input() showName?: boolean = true; 也有效。 - Matthias Tylkowski
3
我在想,@Input() showName: boolean; 和常规的有什么区别?然后检查是否为null?我的意思是,有什么不同吗? - Royi Namir
1
@RoyiNamir 最重要的是,它是一种文档形式。通过放置 ? 或不放置 ?,您可以传达您的组件是否能够处理此输入未定义或不是未定义的信息。此外,我认为它被 strictNullChecks 编译器选项所识别。https://christianliebel.com/2017/05/angular-typescript-writing-safer-code-with-strictnullchecks/ - masterxilo
1
@MatthiasTylkowski 如果你设置了默认值,那么将其设置为可选项就没有意义,因为它总是会被设置为某个值。 - rooby
1
@MatthiasTylkowski Optional 表示 showName 属性可能不存在,但默认设置为 true 意味着它将始终存在,因此没有必要将其设置为可选。 (null 在此处无关紧要,设置为 null 的属性仍然存在。可选仅与定义或未定义有关。)- 这里的可选不是指是否必须传入输入(默认情况下输入是可选的),而是指类上是否必须存在 showName 属性。 - rooby
显示剩余3条评论

33

默认情况下,输入值是可选的。只有在尝试访问未实际传递的输入属性(因为这些输入是undefined)时,您的代码才会失败。

您可以实现OnChanges或将输入设置器替换为属性,以在实际传递值时执行您的代码。

export class child {

    @Input set showName(value: boolean) {
      this._showName = value;
      doSomethingWhenShowNameIsPassed(value);
    }

    constructor() { }
}

请查看 @galvan 的评论,似乎是一个更好的解决方案。 - Sumit Agarwal
7
你为什么认为这样做更好?当父组件必须向服务器发出请求并且仅在此之后将值传递给子组件时,可能会在调用了ngAfterViewInit()方法之后相当长的时间才能传递。尽管在你的具体情况下ngAfterViewInit()可能有效,但一般情况下我不建议这样做。 - Günter Zöchbauer
你是说,如果我在客户端动态更改值?根据你的解释,我应该在子指令中调用setter方法吗? - Sumit Agarwal
1
你不需要调用setter,但如果你有<child [showName]="propOnParent">并且propOnParent在某个异步调用完成后初始化,那么Angular会更新<child>中的showName输入或在它是一个setter的情况下,调用setter并传入更新后的值。 - Günter Zöchbauer
如果你只关心静态绑定的值,比如在你的问题中的 true,那么 ngOnInit() 生命周期钩子比 ngAfterViewChecked() 更常用。 - Günter Zöchbauer
提示:如果您创建了一个没有getter的setter,Typescript仍然允许您调用getter,但会返回undefined。如果您需要该值,则必须添加get showName() { return this._showName; }。不幸的是,这就是Typescript / Javascript的工作方式! - Simon_Weaver

1
你有两个选项。
1)如果子组件的输入为空时不需要显示子组件,可以在子组件上使用 *ngIf
(原文已为中文,无需翻译)请注意保留 html 标签。
 <parent>
    <child *ngIf="true" [showName]="true"></child> //passing parameter
    <child></child> //not willing to passing any parameter
</parent>

2) 如果孩子没有任何输入就被显示出来,您可以使用修改过的setter来检查输入变量的存在。

在child.ts文件中:

private _optionalObject: any;
@Input()
set optionalObject(optionalObject: any) {
    if(optionalObject) this._optionalObject = optionalObject;
}
get optionalObject() { return this._optionalObject; }

请查看 @galvan 的评论,似乎是一个更好的解决方案。 - Sumit Agarwal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接