我随时从Material Autocomplete中选择一个选项,它会对服务器进行额外的HTTP GET调用。选择下拉选项的理想结果应该是填充输入。
从服务器动态检索下拉选项。
HTML :
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="search item" aria-label="Item1" matInput [formControl]="searchTerm" [matAutocomplete]="auto1">
<mat-autocomplete #auto1="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let item of searchResult" [value]="item.Id">
{{ item.Name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
打字稿:
searchTerm : FormControl = new FormControl();
searchResult = [];
constructor(private service: AppService){
this.searchTerm.valueChanges
.debounceTime(400)
.subscribe(data => {
this.service.search_word(data).subscribe(response =>{
this.searchResult = response
})
其他一切都很好。唯一的问题是当选择自动完成选项时意外额外调用服务器。
快速更新:没有答案完全解决了这个问题。但是,我把它缩小到可能是displayWith的问题。
答案 0 :(得分:1)
您的问题正在发生,因为下拉选项会更改searchTerm
表单控件的值;从而在该表单控件上发出valueChanges
可观察事件的事件。
有几种方法可以在窗体控件上的valueChanges
observable中构建一些逻辑,以便忽略这个不需要的Http GET请求。
天真的解决方案
天真的解决方案是存储下拉选项选择值,并跳过selectionValue === searchTerm.value
的可观察逻辑。
var optionSelection; // set this value on selection of a dropdown option
this.searchTerm.valueChanges
.debounceTime(400)
.subscribe(data => {
if (optionSelection !== searchTerm.value) {
this.service.search_word(data).subscribe(response =>{
this.searchResult = response
})
}
})
更好的解决方案
FormControl类有一个setValue
函数,它有一个可选参数来指定是否向valueChanges
observable发出事件。
setValue(value: any, options: {
onlySelf?: boolean;
emitEvent?: boolean;
emitModelToViewChange?: boolean;
emitViewToModelChange?: boolean;
} = {}): void
通过更改下拉选项选择以使用setValue
设置searchTerm表单控件值,您可以传递可选的emitEvent: false
参数并停止发出此额外的可观察事件。
searchTerm.setValue(dropdownValue, { emitEvent: false });
如果emitEvent为false,则此更改将导致不发出FormControl上的valueChanges事件。默认为true(因为它落到updateValueAndValidity)。
答案 1 :(得分:1)
问题在于有两个事件被触发的事件...我已经为它制造了一个错误,但它应该如何工作。希望这会有所帮助。
这是我的解决方案:
HTML:
<mat-option *ngFor="let item of searchResult" [value]="item.Id" (onSelectionChange)="onSelectionChange($event, item.Id)"> // or item
在您的组件中:
private onSelectionChange(_event: any, _id: any) {
if (_event.isUserInput === true) { // there are two events one with true and one with false;
this.service.search_word(_id).subscribe(response =>{
this.searchResult = response
})
}
答案 2 :(得分:1)
您可以在输入文字中使用Jobs/Honda
,然后就可以像这样使用
(keyup)="onKeyUp($event)"
答案 3 :(得分:0)
从Angular Material版本7.2.0开始,对于MatAutocomplete,您有一个名为“ optionSelected”的新EventEmitter
所以您的HTML应该是这样的:
<mat-autocomplete (optionSelected)="optionSelected($event)" #auto1="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let item of searchResult" [value]="item.Id">
{{ item.Name }}
</mat-option>
</mat-autocomplete>
和您的.ts:
private optionSelected(event) {
console.log(event)
}
您将在optionSelected()
方法内处理它。
尝试一下,因为我没有您的所有代码。让我知道它是否无效。
答案 4 :(得分:0)
这是一种棘手的方法,将选项值设置为 object 而不是 string ,然后在输入更改时可以确定是通过键入还是选择来确定。
<!-- Template -->
<mat-option *ngFor="let item of searchResult" [value]="item">
// Component
this.searchTerm.valueChanges.subscribe(modelValue => {
if (typeof modelValue === 'string') {
this.searchUser.next(modelValue.toString());
} else {
this.searchTerm.setValue(modelValue.Id, {
emitEvent: false
});
}
});
答案 5 :(得分:0)
您可以使用keyup
代替valueChanges
。以下是我解决相同问题的方法。请记住,此示例在此处显示了我使用mat-autocomplete
进行键盘锁的用例。
import { ViewChild, ElementRef } from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime, tap, switchMap, map, filter, distinctUntilChanged } from 'rxjs/operators';
添加mat-autocomplete
html,请注意,这还包括在远程进行HTTP调用期间加载微调器,但可以将其删除。
<mat-form-field>
<input matInput #searchInput placeholder="" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngIf="isLoading">
<mat-spinner diameter="50"></mat-spinner>
</mat-option>
<ng-container *ngIf="!isLoading">
<mat-option *ngFor="let data of filteredData | async" [value]="data.modelValue">
<span>{{ data.modelValue }}</span>
</mat-option>
</ng-container>
</mat-autocomplete>
</mat-form-field>
将以下内容添加到您的控制器中。
isLoading: boolean;
@ViewChild('searchInput') searchInput: ElementRef;
filteredData: searchModel[] = [];
设置keyup
事件监听器。
fromEvent(this.searchInput.nativeElement, 'keyup').pipe(
map((event: any) => {
return event.target.value; // Map search input value
}),
filter(res => res.length > 3), // If character length greater then 3
debounceTime(500),
distinctUntilChanged(), // If previous search is different from current
tap((val) => {
this.isLoading = true;
this.filteredData = [];
}),
switchMap(value =>
this.service.search(value).pipe(
finalize(() => this.isLoading = false)
)
)
).subscribe(data => {
this.filteredData = data;
});