为啥从内部组件中更改 @Input 变量会导致它无法检测到来自外部组件的新更改?

Posted

技术标签:

【中文标题】为啥从内部组件中更改 @Input 变量会导致它无法检测到来自外部组件的新更改?【英文标题】:Why changing the @Input variable from within the internal component causes its failure to detect new changes from external component?为什么从内部组件中更改 @Input 变量会导致它无法检测到来自外部组件的新更改? 【发布时间】:2018-07-23 18:32:18 【问题描述】:

我正在尝试在下面的“EditDialogComponent”中设置 CSS 类(这是一个模式视图),具体取决于从“AppComponent”设置的名为“showMe”的输入属性:

    html 代码:
    <div [ngClass]="showMe? 'ui active modal': 'ui modal'">
      <i class="close icon"></i>
      <div class="header">
        Edit
      </div>
      <div class="actions">
        <div (click)="cancel()" class="ui black deny button">
          Cancel
        </div>
        <div class="ui positive right labeled icon button">
          OK
          <i class="checkmark icon"></i>
        </div>
      </div>
    </div>

2。打字稿代码:

import  Component, Input, Output, EventEmitter, OnInit  from '@angular/core';

@Component(
  selector: 'edit-dialog',
  templateUrl: './edit-dialog.component.html',
  styleUrls: ['./edit-dialog.component.css']
)
export class EditDialogComponent implements OnInit 

  _showMe: boolean

  @Input() subject: string

  @Input() set showMe(value: boolean) 
    this._showMe = value
    window.alert('Trying to show modal')
  

  get showMe() : boolean 
    return this._showMe
  

  cancel() 
    this._showMe = false
  

  constructor()  

  ngOnInit() 
  


以下是用于将“EditDialogComponent”包含到“AppComponent”中的代码:

    HTML 代码:
        <button (click)='edit()'>Edit</button>

    <edit-dialog [showMe]="show_edit_modal" subject='foobar'></edit-dialog>
    TypeScript 代码:
    edit() 
        window.alert('Trying to show modal')
        this.show_edit_modal = true 

问题是在showMe @Input() 从EditDialogComponent 内部更改后(通过单击模式的“取消”按钮调用),它无法检测到数据绑定的更改(即AppComponent.edit() 调用的 show_edit_modal)(当我点击 AppComponent 的 Edit 按钮时显示“尝试显示模式”),因为来自 EditDialogComponent.ngOnChanges() 的警报停止显示。

为什么从内部组件更改@Input 变量会导致它无法检测到来自外部组件的新更改?

【问题讨论】:

【参考方案1】:

@Input 只是一种单向绑定。如果您还想更改父组件中的值,则必须创建两种方式的数据绑定。为此,您必须创建一个与输入名称相同的输出(在您的情况下为 showMe)+ 更改(例如:showMeChange: EventEmitter&lt;any&gt;),并在您的 showMe 设置器中发出。

现在在您的父组件中,您可以像 ngModel 一样使用它。

&lt;edit-dialog [(showMe)]="show_edit_modal" subject='foobar'&gt;&lt;/edit-dialog&gt;

我在这里创建了一个完整的示例:https://stackblitz.com/edit/angular-c83djz

【讨论】:

感谢您的解决方案。但是我不明白为什么我需要双向数据绑定,尽管我不需要父级从 EditDialogComponent 读取值。或者正在发出为父级保持@Input 对象ID 最新所需的输入 因为重新渲染组件时将再次使用父值作为@Input,并且如果您不进行两种方式的数据绑定,该值将保持不变。这就是为什么您需要发出更改并更新父级中的值。 该值需要在子级中更新。父级只是一个 setter。【参考方案2】:

这是按预期工作的。 @Input() 不会导致检测到更改。

showMe="show_edit_modal"

是 Angulars 更改检测检查的内容。

更好

[showMe]="show_edit_modal"

实际传递布尔值而不是字符串

你能做的就是让showMe成为一个setter

_showMe:boolean;
@Input() set showMe(val: boolean) 
  this._showMe = val;
  window.alert('Trying to show modal')


get showMe() : boolean 
  return this._showMe;

【讨论】:

同样的问题是什么意思?更新属性时无法调用ngOnChanges。您需要将代码移动到 setter。 对不起,我把@Input() showMe换成了你上面提到的代码。但点击取消后,“尝试显示模式”的警报停止显示。 请编辑您的问题并在其中添加您现在拥有的代码。 set 和属性之间没有下划线。应该是 set showMe 而不是 set_showMe 我知道。我刚刚更新了问题(对不起代码格式)。 使用this._showMe = false;,您可以绕过设置器并直接访问支持属性。应该是this.showMe = false

以上是关于为啥从内部组件中更改 @Input 变量会导致它无法检测到来自外部组件的新更改?的主要内容,如果未能解决你的问题,请参考以下文章

在 ngOnInit() 中使用数据绑定从本地 JSON 文件读取数据会导致未定义的变量

为啥从其他文件导入组件会导致“Invariant Violation: Element type is invalid”错误?

为啥Vue会更新父级中的变量-未使用事件

为啥我的输入变量属性未定义(Angular)

从 JS 更改 css 变量的值会导致奇怪的行为

为啥我的 SQL 查询会出现内部服务器错误?