FormGroup.valuesChanges с пользовательским вводом возвращает предыдущее значение

пример 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;
    });
  }
}

person Ced    schedule 09.04.2020    source источник


Ответы (1)


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

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

Or

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

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

  onChange(value: string) {
            this.writeValue(value);
            this.onChangeFn(value);
            this.onTouchedFn();
}
person wessam yaacob    schedule 09.04.2020
comment
Хотя первый пункт неверный, а второй правильный - person Ced; 09.04.2020
comment
это неправильно, потому что я не хочу уведомлять о размытии, это зависит от updateOn, а updateOn не всегда размыто. Но я соглашусь, если вы измените - person Ced; 09.04.2020
comment
вы можете сделать как (ввод), так и (размытие), я изменю :) - person wessam yaacob; 09.04.2020
comment
на самом деле вы должны переместить onTouchedFn из onChange, потому что (ввод) событие срабатывает каждый раз, когда вы меняете значение, и вы не хотите уведомлять о событии размытия при каждом нажатии клавиши - person wessam yaacob; 09.04.2020