【问题标题】:Proper way to propagate computed value on Angular2在 Angular2 上传播计算值的正确方法
【发布时间】:2017-05-04 16:20:48
【问题描述】:

我想使用 @Input 属性的计算值

但传播初始值效果不佳。

https://plnkr.co/edit/1MMpOYOKIouwnNc3uIuy

我创建了App(具有模板驱动表单的根组件)和NumComponent(仅保存类型值的子组件)组件。

当我像[useThree]="true" 一样将属性传递给NumComponent 时,我想将默认值'3' 设置为NumComponent

但我找不到不使用setTimeout的方法

有没有办法在没有 setTimeout 的情况下传播初始值?


于 5 月 5 日编辑

应用组件

@Component({
  selector: 'my-app',
  template: `
    <div>
      <form novalidate #form="ngForm">
        <app-num name="num" ngModel [useThree]="true"></app-num>
      </form>
      <pre>{{form.value | json}}</pre>
    </div>
  `
})
export class App {}

数字组件

export const NumValueAccessor = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => NumComponent),
  multi: true
};

@Component({
  selector: 'app-num',
  template: `<input [(ngModel)]="num" type="text" (ngModelChange)="updateValue()" />`,
  providers: [NumValueAccessor]
})
export class NumComponent implements ControlValueAccessor {
  num = 0;

  // I want set literal number 3 to `num` property
  // when `useThree` is true.
  @Input() useThree = false;

  onChange = (_: any) => {};

  updateValue(num = this.num) {
    this.onChange(String(num));
  }

  writeValue(value: string): void {
    if (this.useThree) {
      /**********
       * ISSUE
       **********/
      // this code is not work. after code ran, `NumComponent` has
      // value 3 but AppComponent's internal FormComponent value
      // is '' (empty string)
      // this.num = 3;
      // this.updateValue(3);

      // ran code with `setTimeout` solve this problem. but
      // I don't want using setTimeout for this feature.
      // setTimeout(() => {
      //   this.num = 3;
      //   this.updateValue(3);
      // }, 0);

      // Is there any way to propagate computed initial value?
      this.num = 3;
      this.updateValue(3);

      /**********
       * ISSUE
       **********/

      this.useThree = false;
      return;
    }
    this.num = Number(value);
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {}

  setDisabledState(isDisabled: boolean): void {}
}

似乎父组件在初始化生命周期时没有实现传播值。

【问题讨论】:

  • 请在minimal reproducible example中提供所有相关代码在问题本身中不仅在第三方网站上
  • @MikeMcCaughan 我用 cmets 添加了相关代码。我为需要执行演示的人维护以前的 plunker 链接。 :)
  • 模板驱动的表单是异步的。 registerOnChange 函数在您在writeValue 中调用this.updateValue 后执行。 NgModel 不会同步添加表单控件 — 它是在微任务中添加的 (promise.then)。您只能通过像这样plnkr.co/edit/A4xBldIIj58fPFjzndEW?p=preview 安排另一个微任务来等待
  • @yurzui 非常感谢 :)

标签: javascript angular typescript


【解决方案1】:

我不确定我是否完全理解了这个问题,但您正在寻找的一种可能的解决方案可能是

private _useThree = false;
@Input() set useThree(value: boolean) {
     this._useThree = value;
     if (this._useThree) {
         this.num = 3;
     }
}

这样,任何时候你想从父组件设置输入useThree属性的值,你实际上是执行上面定义的setter方法的代码。

【讨论】:

  • 我将值更新代码移到了useTree setter,但它也与前一个有同样的问题。
猜你喜欢
  • 1970-01-01
  • 2019-07-16
  • 2012-08-13
  • 2017-09-28
  • 1970-01-01
  • 2020-06-19
  • 1970-01-01
  • 1970-01-01
  • 2019-10-12
相关资源
最近更新 更多