![](/img/trans.png)
[英]Angular 7 - How to disable Save button until Value from Dropdown and field is not populated ? Or all form is not populated?
[英]How to stop or disable ngbTypeahead input field from opening on focus until it finishes mapping all the data
单击输入字段时,我需要预先输入以显示前 5 个结果。 我已经使用 ngbTypeahead 文档制定了解决方案。
app.component.html
<div class="form-group g-0 mb-3">
<input id="typeahead-prevent-manual-entry" type="text" class="form-control"
placeholder="Big dataset"
formControlName="bigDataset"
[ngbTypeahead]="search"
[inputFormatter]="valueFormatter"
[resultFormatter]="valueFormatter"
[editable]="false"
[focusFirst]="false"
(focus)="stateFocus$.next($any($event).target.value)"
(click)="stateClick$.next($any($event).target.value)"
#instance="ngbTypeahead" />
</div>
app.component.ts
type BigDataset: {
id: string,
name: string
}
export class AppComponent implements OnInit {
dataset: BigDataset[];
@ViewChild('instance', {static: true}) instance: NgbTypeahead;
focus$ = new Subject<string>();
click$ = new Subject<string>();
constructor(
private formBuilder: FormBuilder,
) { }
ngOnInit(): void {
this.dataForm = this.formBuilder.group({
bigDataset: ["", [Validators.required]],
});
}
getBigDataset() {
//Excluded for simplicity. This returns a set of objects (~3000)
//of type BigDataset and assigns it to this.dataset.
}
valueFormatter = (value: any) => value.name;
search: OperatorFunction<string, readonly BigDataset[]> = (text$: Observable<string>) => {
const debouncedText$ = text$.pipe(debounceTime(100), distinctUntilChanged());
const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen()));
const inputFocus$ = this.focus$;
return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(map(term => (term === '' ? this.dataset
: this.dataset.filter(data => data.name.toLowerCase().indexOf(term.toLowerCase()) > -1)).slice(0, 5))
);
};
}
现在这有效。 但是,问题是如果我在页面初始化后立即单击输入字段,我会收到此错误:
ERROR TypeError: Cannot read properties of undefined (reading 'slice')
at org-address.component.ts:93:109
at map.js:7:1
at OperatorSubscriber._next (OperatorSubscriber.js:9:1)
at OperatorSubscriber.next (Subscriber.js:31:1)
at subscribe._OperatorSubscriber__WEBPACK_IMPORTED_MODULE_1__.OperatorSubscriber.innerComplete (mergeInternals.js:25:1)
at OperatorSubscriber._next (OperatorSubscriber.js:9:1)
at OperatorSubscriber.next (Subscriber.js:31:1)
at Subject.js:31:1
at errorContext (errorContext.js:19:1)
at Subject.next (Subject.js:26:21)
据我所知,这是因为预输入试图在完成 map function 之前显示数据。 问题是如果我决定增加数据集,map 所需的时间可能会增加,因此等待未知的时间直到完成该过程不是一个选项。 我想禁用该字段或使用其他解决方案,直到它完成映射过程。
我曾尝试禁用表单字段并在映射过程之后使用 finalize() 启用它,但我似乎犯了一个错误并且该字段保持禁用状态。
search: OperatorFunction<string, readonly BigDataset[]> = (text$: Observable<string>) => {
this.dataForm.get('bigDataset')?.disable();
const debouncedText$ = text$.pipe(debounceTime(100), distinctUntilChanged());
const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen()));
const inputFocus$ = this.focus$;
return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
finalize(() => this.dataForm.get('bigDataset')?.enable()),
map(term => (term === '' ? this.dataset
: this.dataset.filter(data => data.name.toLowerCase().indexOf(term.toLowerCase()) > -1)).slice(0, 5))
);
};
对此的任何帮助将不胜感激。
我的一个朋友实际上给了我一个非常简单的解决方法,就是在数据过滤之后(拼接过程之前)添加可选链接。 添加'? 在调用 slice 方法之前,如果它尝试在过滤过程完成之前返回值,它就像一个魅力一样工作并且停止给出错误。
search: OperatorFunction<string, readonly BigDataset[]> = (text$: Observable<string>) => {
const debouncedText$ = text$.pipe(debounceTime(100), distinctUntilChanged());
const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen()));
const inputFocus$ = this.focus$;
return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(map(term => (term === '' ? this.dataset
: this.dataset.filter(data => data.name.toLowerCase().indexOf(term.toLowerCase()) > -1))?.slice(0, 5))
);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.