EventEmitter 持续发出值
EventEmitter is continuously emitting the value
我正在尝试创建一个指令,该指令在用户输入时显示加载栏,并在用户停止输入时提交输入。
import { Directive, EventEmitter, Input, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { debounceTime, tap } from 'rxjs/operators';
import { Subscription } from 'rxjs';
@Directive({
selector: '[appAutoSave]',
})
export class AutoSaveDirective {
@Input() formGroup!: FormGroup;
private _state!: 'loading' | 'synced' | 'modified' | 'error';
@Output() stateChange = new EventEmitter<string>();
@Output() onSubmit = new EventEmitter();
@Output() formError = new EventEmitter<string>();
private formSub!: Subscription;
ngOnInit() {
this.preloadData();
this.autoSave();
}
preloadData() {
this.formGroup.markAsPristine();
// this.state = 'synced';
}
// Autosaves form changes
autoSave() {
console.log('inside changes');
this.formSub = this.formGroup.valueChanges
.pipe(
tap(change => {
this.state = 'modified';
}),
debounceTime(2000),
tap(change => {
if (this.formGroup.valid && this._state === 'modified') {
// this.onSubmit.emit();
this.state = 'synced';
}
}),
)
.subscribe();
}
set state(val: any) {
this._state = val;
this.stateChange.emit(val);
if (val === 'synced') {
this.onSubmit.emit();
}
}
ngOnDestroy() {
this.formSub.unsubscribe();
}
}
changeState(event: string) {
this.changeHandler.emit(event);
if (event === 'synced') { // condition
this.submit();
}
}
如果我删除上面的 if 条件,一切正常。但是当值同步并且用户停止输入时,我必须调用提交函数。
<form
[formGroup]="situationFormGroup"
appAutoSave
(stateChange)="changeState($event)"
>
我会从削减这个指令责任开始。
It is doing to much .. 'loading' | 'synced' | 'modified' | 'error'.
I would suggest creating 3 directives:
(Keep it SOLID)
- 加载指令
- 错误指令
- 打字指令
并且与 TypingDirective 相比,您只会在 form.valueChanges
的开头显示该加载程序,而在 debounceTime(2000)
之后的 tap(this.onSubmit.emit(...))
中则不会。
在您的 autosave 方法中,您在 pipe 函数中编写了 tap 运算符,如下所示:
tap(change => {
this.state = 'modified';
})
上面的代码对 FormGroup 中的每个 valueChanges 都会设置 state,这将发出一个 stateChange 事件。因此,对于每个更改,EventEmitter 都会发出值(请参阅 state 的 setter 中的代码)
为避免这种情况,请执行以下操作:
tap(change => {
if(this._state!=='modified'){
this.state = 'modified';
}
})
我正在尝试创建一个指令,该指令在用户输入时显示加载栏,并在用户停止输入时提交输入。
import { Directive, EventEmitter, Input, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { debounceTime, tap } from 'rxjs/operators';
import { Subscription } from 'rxjs';
@Directive({
selector: '[appAutoSave]',
})
export class AutoSaveDirective {
@Input() formGroup!: FormGroup;
private _state!: 'loading' | 'synced' | 'modified' | 'error';
@Output() stateChange = new EventEmitter<string>();
@Output() onSubmit = new EventEmitter();
@Output() formError = new EventEmitter<string>();
private formSub!: Subscription;
ngOnInit() {
this.preloadData();
this.autoSave();
}
preloadData() {
this.formGroup.markAsPristine();
// this.state = 'synced';
}
// Autosaves form changes
autoSave() {
console.log('inside changes');
this.formSub = this.formGroup.valueChanges
.pipe(
tap(change => {
this.state = 'modified';
}),
debounceTime(2000),
tap(change => {
if (this.formGroup.valid && this._state === 'modified') {
// this.onSubmit.emit();
this.state = 'synced';
}
}),
)
.subscribe();
}
set state(val: any) {
this._state = val;
this.stateChange.emit(val);
if (val === 'synced') {
this.onSubmit.emit();
}
}
ngOnDestroy() {
this.formSub.unsubscribe();
}
}
changeState(event: string) {
this.changeHandler.emit(event);
if (event === 'synced') { // condition
this.submit();
}
}
如果我删除上面的 if 条件,一切正常。但是当值同步并且用户停止输入时,我必须调用提交函数。
<form
[formGroup]="situationFormGroup"
appAutoSave
(stateChange)="changeState($event)"
>
我会从削减这个指令责任开始。
It is doing to much .. 'loading' | 'synced' | 'modified' | 'error'. I would suggest creating 3 directives: (Keep it SOLID)
- 加载指令
- 错误指令
- 打字指令
并且与 TypingDirective 相比,您只会在 form.valueChanges
的开头显示该加载程序,而在 debounceTime(2000)
之后的 tap(this.onSubmit.emit(...))
中则不会。
在您的 autosave 方法中,您在 pipe 函数中编写了 tap 运算符,如下所示:
tap(change => {
this.state = 'modified';
})
上面的代码对 FormGroup 中的每个 valueChanges 都会设置 state,这将发出一个 stateChange 事件。因此,对于每个更改,EventEmitter 都会发出值(请参阅 state 的 setter 中的代码)
为避免这种情况,请执行以下操作:
tap(change => {
if(this._state!=='modified'){
this.state = 'modified';
}
})