如何在设置或获取FormControl之前拦截它的值?

时间:2017-08-08 23:27:58

标签: angular ionic-framework ionic2 angular2-forms angular-reactive-forms

这个问题非常明显。我想拦截FormControl的value属性的传入值,并能够截取它与其连接的HTML控件的传出值。

我们说我有一个名为" firstName"的FormControl。然后我将它连接到文本框:

<input type="text" formControlName="firstName" />

默认情况下,当用户在文本框中输入值并提交时,FormControl的值将设置为文本框中的值。有没有什么方法可以拦截设置的值并在设置之前修改它?

同样,有没有办法拦截FormControl发送给HTML控件的值?例如,如果我将FormControl的值设置为某个值,但我想修改文本框中显示的值。

我知道我可以使用ngModel充当表单和控件之间的中介,但是当使用多个控件时,这会变得很麻烦。我也知道你可以创建自己的控件并实现ControlValueAccessor,但这也很麻烦,因为我必须为我想要使用的每个控件创建一个相应的控件。

有关我提出此问题的原因的详情,请参阅https://github.com/ionic-team/ionic/issues/7121

3 个答案:

答案 0 :(得分:1)

您可以使用onBlur来调用函数(即modifyValue()),然后利用patchValue来修改值:

<input type="text" onblur="modifyValue()" formControlName="firstName" />

modifyValue() {
    this.form.patchValue({
      firstName: this.form.firstName //modify firstName here
    })
}

如果可行,您可以创建一个通用函数并传递键/值以便对其进行修补,而无需创建一堆特定函数

<input type="text" onblur="modifyValue('firstName')" formControlName="firstName" />

  modifyValue(key) {
      this.form.controls[key].patchValue(this.form.controls[key] // modify value here)
  }

答案 1 :(得分:1)

您可以编写一个可重用的指令,以拦截来自视图和进入视图的值:

const MODIFIER_CONTROL_VALUE_ACCESSOR: Provider = {
  provide: NG_VALUE_ACCESSOR,
  useExisting: forwardRef(() => ValueModifierDirective),
  multi: true,
};

@Directive({
  selector: '[valueModifier]',
  host: { '(keyup)': 'doSomething($event)' },
  providers: [MODIFIER_CONTROL_VALUE_ACCESSOR],
})
export class ValueModifierDirective implements ControlValueAccessor {

  @Input() valueModifier: [Function, Function];

  private writeToForm;

  constructor(public _el: ElementRef) { }

  doSomething(event: Event) {
    const viewToForm = this.valueModifier[0];
    this.writeToForm(viewToForm(event.target.value));
  }

  registerOnChange(fn: (value: any) => void) {
    this.writeToForm = fn;
  }

  registerOnTouched(fn: any) {
    // nothing to do
  }

  writeValue(value: any) {
    const formToView = this.valueModifier[1];
    this._el.nativeElement.value = formToView(value);
  }
}

要使用它,只需将指令添加到在其上应用formControlName的同一元素上并传递transform-functions:

@Component({
  selector: 'my-app',
  template: `
  <form [formGroup]="form">
  <input [valueModifier]="[viewToForm, formToView]" name="value" type="text" formControlName="input"  />
  <button (click)="random()">Set Random Value</button>
  </form>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  form = new FormGroup({
    input: new FormControl(1)
  });
  viewToForm = (text: string) => "toForm" + text;
  formToView = (text: string) => "toView" + text;

  constructor() {
    this.form.valueChanges.subscribe(value => console.log(value));
  }

  random () {
    this.form.patchValue({
      input: Math.random()
    })
  }
}

实时示例(Stackblitz):

https://stackblitz.com/edit/angular-afmkxl?file=src%2Fapp%2Fapp.component.ts

以上内容适用于文本输入。我认为您可以为其他类型的输入编写类似的指令。

答案 2 :(得分:0)

您可以创建指令 inject the formControl in the directive,然后使用 emitModelToViewChangeemitViewToModelChangesetValue 选项。

像这样:

@Directive({
  selector: '[valueModifier]',
})
export class ValueModifierDirective {
  constructor(private control: NgControl) {}

  private setValueOfModel() {
    this.control.control!.setValue('Custom Value', { emitModelToViewChange: false });
  }
}

此解决方案适用于任何类型的表单输入(输入、选择、复选框等)。