FormGroup.valuesChanges, с пользовательским вводом, возвращает предыдущее значение - PullRequest
0 голосов
/ 09 апреля 2020

пример stackblitz

При использовании formGroup с пользовательским вводом наблюдаемое значение valueChanges запускается со старым значением каждый раз, когда пользователь вводит. Это происходит только с опцией updateOn: blur.

Ожидаемый результат будет иметь текущее значение.

Итак, у меня есть помощник AbstractControlValueAccessor:

export class AbstractInput implements ControlValueAccessor {
    @Input() value: any = '';
    public disabled: boolean;
    protected onTouchedFn = (any?: any) => { };
    protected onChangeFn = (any?: any) => { };

    constructor() {}

    // Called when patchValue or setValue is called on the form control
    // Allows Angular to update the model
    writeValue(value: any): void {
        this.value = value;
    }

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

    registerOnTouched(fn: any): void {
        this.onTouchedFn = fn;
    }

    setDisabledState?(isDisabled: boolean): void {
        this.disabled = isDisabled;
    }

}

У меня есть пользовательский ввод

@Component({
  selector: 'custom-input',
  template: `
        {{ value | json }}
    <input 
    #inp
    inputApp
    type="text"
    [value]="value"
    (input)="onChange(inp.value)"/>
  `,
  providers: [ 
    makeAccessorProvider(CustomInputComponent)
  ]
})
export class CustomInputComponent extends AbstractInput  {

  onChange(value: string) {
        this.onTouchedFn();
        this.writeValue(value);
        this.onChangeFn(value);
    }

    onTouched() {
        this.onTouchedFn();
    }
}

и у меня есть компонент, который использует пользовательский ввод и проверяет, когда значение formGroup изменяется. Однако значение в консоли всегда является предыдущим значением.

@Component({
  selector: 'my-app',
  template:`
    <form [formGroup]="group">
      <custom-input formControlName="name"></custom-input>
    </form>`
})
export class AppComponent implements OnInit {
  group: FormGroup;
  value: any;
  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.group = this.fb.group({
      name: ['initial value']
    }, { updateOn: 'blur' });
    this.group.valueChanges.subscribe(value => {
      console.log(this.group.value);
      this.value = this.group.value;
    });
  }
}

1 Ответ

1 голос
/ 09 апреля 2020

Первое: вам нужно добавить (размытие) событие в свой пользовательский элемент управления, чтобы вызвать метод onTouchedFn, когда элемент потерял фокус.

Второе: вам нужно изменить порядок вызова событий в Метод onChange, поэтому вам нужно вызвать this.onChangeFn(value); до this.onTouchedFn();

или

Отделить this.onTouchedFn() для вызова в пользовательском событии размытия ввода и просто оставить onChangeFn(value) внутри onChange method

в вашем коде происходит то, что вы вызываете метод onTouchedFn, поэтому вы хотите уведомить элемент управления формы о том, что ваш входной элемент вызвал событие размытия (но вы не передали окончательное значение), так что this.group.valueChanges.subscribe не сработает после этого, вы вызываете onChangeFn со значением, которое будет кэшироваться для следующего события размытия, затем вы снова вводите новое значение, вызывая onTouchedFn, поэтому в этот момент this.group.valueChanges.subscribe сработает с последними переданными данными, которые предыдущее значение

  onChange(value: string) {
            this.writeValue(value);
            this.onChangeFn(value);
            this.onTouchedFn();
}
...