Search code examples
angularangular2-componentsangular2-changedetection

Angular2 - notify child that parent object changed so child can refire an ngIf inside its template


I have a similar issue to this question, but it seems that question is out of date as neither of the 2 answers work for me.

The child component is simply rendering data from a complex object called Proposal passed as an input (it has no user controls at all, so does not need to fire any events or pass anything out).

@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()
}

The pertinent part of the template is this, iterating an array and checking a property to display different text using *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>

In the parent, the user can click a checkbox to change 'is_fitted' to true or false. The parent is using a domain-drive form. In the ngOnInit of the parent is this code:

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;
    });
  }
);  

which correctly updates the property. I can see that if I console.log it. So the question is, how can I get the child to refire/re-process the *ngIf when the embedded room.is_fitted values change?

I have tried implementing this idea, using ViewChild, so the above code in ngOnInit then becomes:

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);
  }
);

but that does not work either. My notifyChange in the child is called successfully:

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

but the view does not update - the *ngIf logic does not get reprocessed.


Solution

  • I took out all the code and wrote it again from scratch and my very fist attempt now works:

    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;
        });
      }
    ); 
    

    I don't need to notify the child at all. The view updates automatically.

    I was convinced from everything I have read that complex objects do not update deep properties - only if you change the reference to the object itself. But here I am now changing deep properties and I am not notifying the child by calling ngOnChanges, and it works. Go figure.