用户键入时,NgOnChanges会覆盖表单控制值

时间:2019-06-14 17:34:17

标签: javascript angular ngrx angular-reactive-forms ngonchanges

我具有自动完成表单控件:

@Component({
    selector: 'app-autocomplete',
    templateUrl: './app-autocomplete.view.html',
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AutoCompleteFilterComponent implements OnInit, OnDestroy, OnChanges {   
@Input() value: any;
@Output() onChanged = new EventEmitter();
autoCompleteControl: FormControl = new FormControl();
private autoCompleteControlSubscription: Subscription;
constructor() { }

ngOnInit(): void {
    this.autoCompleteControl.setValue(this.value, { emitEvent: false });
    this.autoCompleteControlSubscription = this.autoCompleteControl.valueChanges
        .pipe(
            skipUndefined(),
            filter(value => value.length >= 3),
            distinctUntilChanged(),
            debounceTime(350),
            map(value => {                    
                this.onChanged.emit(value.trim());
            })
        ).subscribe();
}

ngOnChanges(changes: SimpleChanges): void {
    if (!changes.value.firstChange) {
        this.autoCompleteControl.setValue(changes.value.currentValue);
    }
}

ngOnDestroy(): void {
    if (this.autoCompleteControlSubscription) {
        this.autoCompleteControlSubscription.unsubscribe();
    }
}

我从store获取初始值,并将其作为@Input变量传递:

this.value$ = this._store$.select(s=>s.value);
<app-autocomplete [value]="value$ | async"></app-autocomplete>

我遇到的问题是:

  1. 组件加载完毕,我从value传递了初始store
  2. 用户在输入文本字段中输入内容。
  3. 用户停止输入350毫秒(debounce时间)。
  4. 我将emit的值赋给父级,并使用Action + Reducer将值保留在存储中。
  5. this.value $ Observablestore的更改做出反应并触发ngOnChange方法。
  6. 用户继续输入。
  7. store中的值将覆盖用户已经输入的内容。

例如,用户键入“ stri”,然后短暂停顿,然后键入“ string”,但是“ store”值覆盖了他的“ string”值,并且他得到了我之前放入“ store”中的“ stri”值。 有人遇到过吗?我们提出的唯一解决方案是检查焦点并且不设置新值。

1 个答案:

答案 0 :(得分:1)

您正在订阅ngOnInit中的更改:

this.autoCompleteControlSubscription = this.autoCompleteControl.valueChanges

还有ngOnChanges。

this.autoCompleteControl.setValue(changes.value.currentValue);

我将为您尝试做的事情做个尝试:

  1. 在初始化时,您可能需要patchValue并然后设置订阅,以便它们不会相互干扰。

  2. 如果要在不触发表单的valueChanges的情况下修补值,则在没有事件的情况下进行修补:

    this.form.controls[control].patchValue(value, { emitEvent: false });

看看我是如何使用StackBlitz上自己的ControlValueAccessor控件组件执行此操作的。我用writeValue

设置了初始控制值(如果有的话)