ngOnChanges not firing when input property changed

前端 未结 4 522
陌清茗
陌清茗 2020-12-17 19:30

Can you programatically trigger angular\'s change detection when mutating a component property in angular2?

@Compon         


        
相关标签:
4条回答
  • 2020-12-17 20:22

    The reason it doesn’t work can be found in the source code.

    https://github.com/angular/angular/blob/885f1af509eb7d9ee049349a2fe5565282fbfefb/packages/core/src/view/provider.ts

    Where ngOnChanges is called from, and where the SimpleChanges structure is built are very much tied into the component / directive code.

    It’s not just a ‘change tracker’ running that looks over every property however it was set, so ngOnChanges only works for bindings set by parent components.

    This is where ngDoCheck comes in and possibly KeyValueDiffers.

    See also:

    https://netbasal.com/angular-the-ngstyle-directive-under-the-hood-2ed720fb9b61 https://juristr.com/blog/2016/04/angular2-change-detection/

    0 讨论(0)
  • 2020-12-17 20:26

    Trying to manually call change detection or spent a lot of time on a workaround for this is way overkilling, why not creating a function to handle the desired mutation and call it in both ngOnChanges and doSomething? something like:

    @Component({
      selector: 'my-component',
    })
    class MyComponent implements OnChanges {
      @Input() message: string;
      viewMessage: string;
    
      ngOnChanges(changes: { [propertyName: string]: SimpleChange }) {
        for (let propName in changes) {
          if (propName === 'message') {
            this.updateView(this.message);
          }
        }
      }
    
      doSomething() {
        this.viewMessage = 'some important stuff';
      }
    
      updateView(message: string) {
        this.viewMessage = message;
      }
    }
    

    So viewMessage will be the attribute you'll be using and controlling the template.

    0 讨论(0)
  • 2020-12-17 20:31

    There seems to be no way to modify an input binding on this and have it detected during change detection. However it was possible to fix the unit test I was writing by wrapping the whole component in another component

    @ng.Component({
        selector: 'my-host-component',
        template: '<my-component [message]="message" (change)="change.emit($event)"></my-component>'
        directives: [MyComponent]
    })
    class MyHostComponent {
       message: string;
       change = new EventEmitter<any>();
    }
    

    I then ran the test on MyHostComponent, rather than MyComponent.

    I've submitted an issue to angular requesting that a method be added to ComponentFixture so that tests like this are easier to write.

    0 讨论(0)
  • 2020-12-17 20:34

    I was having the same issue, and this is a simple but not very elegant workaround I am using. Pass in another property to force trigger ngOnChanges method

    <div poll-stat-chart [barData]="barData" [changeTrigger]="changeTrigger"></div>
    

    In the parent component class, whenever you want to manually fire the ngOnChanges method on child component, just modify "changeTrigger" property

    ParentComponent Class (poll-stat-chart is the child component)

         @Component({
            directives: [PollStatChartCmp],
            template: `
                <div poll-stat-chart [barData]="barData" [changeTrigger]="changeTrigger">
                </div>
                <button (click)="triggerChild()"></button>
            `
          }
        export class ParentComponent {
            changeTrigger = 1;
            barData = [{key:1, value:'1'}, {key:2, value'2'}];
            triggerChild() {
                this.barData[0].value = 'changedValue';
    
                //This will force fire ngOnChanges method of PollStatChartComponent
                this.changeTrigger ++ ;           
            }
    
        }
    

    And then in child component class, add a property [changeTrigger]

        @Component({
            selector: '[poll-stat-chart]',
            inputs: ['barData', 'changeTrigger'],
            template: `
                <h4>This should be a BAR CHAR</h4>
            `
        })
        export class PollStatChartCmp {
            barData;
            changeTrigger;
            constructor(private elementRef: ElementRef) {
                this.render();
    
            }
    
            ngOnChanges(changes) {
                console.log('ngOnChanges fired');
                this.render();
            }
    
            render() { console.log('render fired');}
    
    }
    
    0 讨论(0)
提交回复
热议问题