【问题标题】:viewchild input property not updated when needed angular 2viewchild 输入属性在需要时未更新角度 2
【发布时间】:2017-03-09 11:17:08
【问题描述】:

我一直在寻找这种行为的某种原因,子组件“Param”中的 Input() 属性的值没有在正确的时间更新,我需要使用更新后的值来调用服务一个参数。通过单击“更新子值”按钮,首先显示 LOG B(带有旧值),然后显示 LOG A(LOG A 它位于属性的设置器中)。

父组件

@Component({
  selector: 'parent',
  template: `
     <child #child [param]="parentParam"></child>
     <button (click)="updateChildValue()">Update child value</button>
`})
export class Parent {
  @ViewChild('child') child: Child;
  public parentParam: number;

  public updateChildValue() {
    this.parentParam = 9;
    this.child.showParam();
  }
}

子组件

@Component({
   selector: 'child',
   template: '' })

export class Child {

   private _param: number;

   public get param() : number {
       return this._param;
   }

   @Input('param')
   public set param(v : number) {
      this._param  = v;
      console.log('LOG A');
      console.log(this.param);        
   }

   public showParam() {
      console.log('LOG B');
      console.log(this.param);
      //I need to call a service using the latest value of param here...
   }
}

期望的行为是首先更新参数的值,然后将该值用作服务的参数。 LOG A 然后 LOG B

【问题讨论】:

    标签: angular angular2-components viewchild


    【解决方案1】:

    使用@Input() 意味着您依赖 Angular2 机制来传播值更改,这意味着您不应该期望您的更改立即生效。事实上,你的this.parentParam = 9; 会经过一个完整的Angular2 周期来更新你孩子的param,而showParam() 函数总是会先执行。

    要完成您的任务,您有 2 个选择:

    1) 将参数直接添加到您的showParam,如:

    // child component
    public showParam(newVal: number) {
      this._param = newVal;
      // do your service call here
    }
    
    // parent component
    public updateChildValue()
    {
      this.parentParam = 9;
      this.child.showParam(9);
    }
    

    2) 在您的 Child 组件上利用 ngOnChanges。每当@Input 发生更改时,Angular2 都会调用此函数。但是,如果您有超过 1 个输入,这可能会出现问题。

    ngOnChanges(changes) {
      console.log(this.param); // new value updated
    }
    

    【讨论】:

    • 感谢您的建议@HarryNinh,我试图在 showParam 方法中使用 ChangeDetectorRef 方法 markForCheck 和 detectChanges。 showParam 只是一个示例,真正的用途是:parentParam 变量将作为参数发送到服务调用中。意味着对 parentParam 的任何更改并不意味着我们需要立即调用该服务。我目前正在寻找像角度 1.x 中的 $digest ,即使知道这是“自动”完成的,你认为我的方式正确吗?
    【解决方案2】:

    我认为这是一个比当前接受的答案更好的答案:

    Angular2+ 的实现方式是使用 ngOnChanges 生命周期钩子:

    父组件:

    @Component({
      selector: 'parent',
      template: `
         <child #child [param]="parentParam"></child>
         <button (click)="updateChildValue()">Update child value</button>
    `})
    export class Parent {
      @ViewChild('child') child: Child;
      public parentParam: number;
    
      public updateChildValue() {
        this.parentParam = 9;
        this.child.showParam();
      }
    }
    

    子组件:

    import { OnChanges, SimpleChanges, SimpleChange } from '@angular/core'
    
    @Component({
       selector: 'child',
       template: '' })
    
    export class Child implements OnChanges {
    
       @Input() param: number;  
    
       
    
       public showParam() {
          console.log('LOG B');
          console.log(this.param);
          //I need to call a service using the latest value of param here...
       }
       
       ngOnChanges(changes: SimpleChanges) {
         const c: SimpleChange = changes.param;
         this.param = c;
       }
    }
    

    【讨论】:

      【解决方案3】:

      只需在父组件中添加一个加载标志,并在 *ngIf 中使用它来显示子组件如下:

      @Component({
        selector: 'parent',
        template: `
           <child *ngIf="!loading" #child [param]="parentParam"></child>
           <button (click)="updateChildValue()">Update child value</button>
      `})
      export class Parent {
        @ViewChild('child') child: Child;
        public parentParam: number;
        loading: boolean;
      
        public updateChildValue() {
          this.loading = true;
          this.parentParam = 9;
          this.loading = false;
          this.child.showParam();
        }
      }
      

      这样,每次加载设置为 false 时,子元素都会使用最新的数据进行初始化。

      经过大量研究后,我发现这是最干净/最高效的解决方案,并且避免了与变更检测和设置器的冲突。

      【讨论】:

        猜你喜欢
        • 2018-08-13
        • 2018-01-21
        • 1970-01-01
        • 2020-01-11
        • 1970-01-01
        • 2021-01-05
        • 1970-01-01
        • 2018-12-30
        • 2021-12-24
        相关资源
        最近更新 更多