【问题标题】:Angular2 - notify child that parent object changed so child can refire an ngIf inside its templateAngular2 - 通知子对象父对象已更改,因此子对象可以在其模板中重新触发 ngIf
【发布时间】:2025-11-24 09:35:01
【问题描述】:

我有与this question 类似的问题,但似乎该问题已过时,因为这两个答案都不适合我。

子组件只是从一个名为 Proposal 的复杂对象中渲染数据,作为输入传递(它根本没有用户控件,因此不需要触发任何事件或传递任何东西)。

@Component({
  selector: 'fb-proposal-document',
  templateUrl: './proposal-document.component.html',
  styleUrls: ['./proposal-document.component.css']
})
export class ProposalDocumentComponent implements OnInit, OnDestroy {
  @Input() proposal: Proposal;

  constructor()
}

模板的相关部分是这样,迭代一个数组并检查一个属性以使用*ngIf显示不同的文本:

<li class="section" *ngFor="let qp of proposal?.quoted_products">
  <li class="section" *ngFor="let room of qp?.rooms">
    ...
    <div class="row">
      <div class="col-md-12">
        Supply
        <span *ngIf="room.is_fitted">
          and install
        </span>
        <span *ngIf="!room.is_fitted">
          only
        </span>                    
      </div>
    </div>
    ...                
  </li>
</li>

在父级中,用户可以单击复选框将“is_fitted”更改为 true 或 false。父级使用域驱动器形式。在父级的ngOnInit 中是这样的代码:

this.myForm.controls['isFitted'].valueChanges.subscribe(
  value => {
    this.proposal.is_fitted = value;
    let qp = this.proposal.quoted_products[this.qpCurrentIndex];
      qp.rooms.forEach(function(room) {
        room.is_fitted = value;
    });
  }
);  

正确更新属性。我可以看到,如果我console.log 它。所以问题是,当嵌入的room.is_fitted 值发生变化时,如何让孩子重新触发/重新处理*ngIf

我已经尝试使用 ViewChild 实现this idea,所以 ngOnInit 中的上述代码变为:

this.myForm.controls['isFitted'].valueChanges.subscribe(
  value => {
    this.proposal.is_fitted = value;
    let qp = this.proposal.quoted_products[this.qpCurrentIndex];
      qp.rooms.forEach(function(room) {
        room.is_fitted = value;
    });
    this.proposalDocument.notifyChange(this.proposal);
  }
);

但这也不起作用。我在 child 中的 notifyChange 调用成功:

  notifyChange(proposal: Proposal) {
    console.log('I changed');
    this.proposal = proposal;
  }

但视图没有更新 - *ngIf 逻辑没有得到重新处理。

【问题讨论】:

标签: angular angular2-components angular2-changedetection


【解决方案1】:

我取出所有代码并从头开始重新编写,我的第一次尝试现在有效:

this.myForm.controls['isFitted'].valueChanges.subscribe(
  value => {
    this.proposal.is_fitted = value;
    let qp = this.proposal.quoted_products[this.qpCurrentIndex];
      qp.rooms.forEach(function(room) {
        room.is_fitted = value;
    });
  }
); 

我根本不需要通知孩子。视图会自动更新。

从我所读到的所有内容中,我确信复杂对象不会更新深层属性 - 只有当您更改对对象本身的引用时。但是在这里,我现在正在更改深层属性,并且不会通过调用 ngOnChanges 来通知孩子,并且它可以工作。去图吧。

【讨论】:

    【解决方案2】:

    更新

    请参阅我的其他答案,因为现在这一切似乎都没有必要。但我会把它留在这里,因为它可能对某人有帮助。


    按照@JBNizet 在问题的 cmets 中提供的链接,我尝试了这个解决方案:

      ngOnChanges(changes: SimpleChanges){
        console.log('I changed ngOnChanges');
        console.log(changes);
        for (let propName in changes){
          if (propName == 'is_fitted') {
            this.proposal.quoted_products.forEach(function(qp) {
              qp.rooms.forEach(function(room) {
                room.is_fitted = changes[propName].currentValue;
              });
            });
          }
        };
      };
    

    所以不是调用我的自定义 notifyChange,而是父调用这个 ngOnChanges 方法,如下所示:

    this.myForm.controls['isFitted'].valueChanges.subscribe(
      value => {
        this.proposal.is_fitted = value;
        this.proposalDocument.ngOnChanges({
            is_fitted: value 
        });
      }
    ); 
    

    新值到达子节点,我可以看到它记录在控制台中,模型上的属性已更新,视图NOW已更新。

    我确实想知道这是否有效,以及我是否应该在这个双循环之前和之后分离和重新连接,如下所示:

    for (let propName in changes){
      if (propName == 'is_fitted') {
        console.log('detaching');
        this.ref.detach();
        this.proposal.quoted_products.forEach(function(qp) {
          qp.rooms.forEach(function(room) {
            room.is_fitted = changes[propName].currentValue;
          });
        });
        this.ref.reattach();
        this.ref.detectChanges();
      }
    };
    

    this official guide 中有关 detectChanges() 的更多信息。

    【讨论】: