我已经安装了ngx-mat-select-search并遵循 StackBlitz 中的示例.
该示例运行良好,就像在 stackblitz 中一样。然后,我更改了代码以使用我的动态数据。我正常加载数据,并且值列在 UI(搜索下拉列表)中,但搜索栏不执行任何操作,也没有错误。
HTML:
<mat-form-field class="selectList-full-width">
<mat-select [formControl]="selectTechnicalRoomCtrl" [placeholder]="'SelectTechnicalRoom' | localize" #singleSelect>
<mat-option>
<ngx-mat-select-search [formControl]="selectTechnicalRoomFilterCtrl" [placeholderLabel]="'Search' | localize"></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let technicalRoom of technicalRooms" [value]="technicalRoom">
{{technicalRoom.nameRoom}}
</mat-option>
</mat-select>
</mat-form-field>
<div class="p-r-25 btn-toolbar">
<button style="margin-left: 10px; padding: 0 1em;" mat-raised-button color="primary" >{{ 'ListPoints' | localize }}</button>
</div>
TS:
export class HomeComponent extends AppComponentBase implements OnInit, AfterViewInit, OnDestroy {
technicalRooms: IdNameTechnicalRoomDto[] = [];
public selectTechnicalRoomCtrl: FormControl = new FormControl();
public selectTechnicalRoomFilterCtrl: FormControl = new FormControl();
/** list of itens filtered by search keyword */
public filteredTechnicalRooms: ReplaySubject<IdNameTechnicalRoomDto[]> = new ReplaySubject<IdNameTechnicalRoomDto[]>(1);
@ViewChild('singleSelect', { static: true }) singleSelect: MatSelect;
protected _onDestroy = new Subject<void>();
constructor(
injector: Injector,
private _technicalRoomsService: TechnicalRoomServiceProxy,
) {
super(injector);
}
ngOnInit() {
this.list();
// set initial selection
this.selectTechnicalRoomCtrl.setValue(this.technicalRooms[10]);
// load the initial itens list
this.filteredTechnicalRooms.next(this.technicalRooms.slice());
// listen for search field value changes
this.selectTechnicalRoomFilterCtrl.valueChanges
.pipe(takeUntil(this._onDestroy))
.subscribe(() => {
this.filterTechnicalRooms();
});
}
list(): void {
this._technicalRoomsService
.getList()
.pipe()
.subscribe(
data => this.technicalRooms = data["result"]
);
}
ngAfterViewInit() {
this.setInitialValue();
}
ngOnDestroy() {
this._onDestroy.next();
this._onDestroy.complete();
}
/**
* Sets the initial value after the filteredTechnicalRooms are loaded initially
*/
protected setInitialValue() {
this.filteredTechnicalRooms
.pipe(take(1), takeUntil(this._onDestroy))
.subscribe(() => {
this.singleSelect.compareWith = (a: IdNameTechnicalRoomDto, b: IdNameTechnicalRoomDto) => a && b && a.id === b.id;
});
}
protected filterTechnicalRooms() {
if (!this.technicalRooms) {
return;
}
// get the search keyword
let search = this.selectTechnicalRoomFilterCtrl.value;
if (!search) {
this.filteredTechnicalRooms.next(this.technicalRooms.slice());
return;
} else {
search = search.toLowerCase();
}
// filter the technicalRooms
this.filteredTechnicalRooms.next(
this.technicalRooms.filter(technicalRoom => technicalRoom.nameRoom.toLowerCase().indexOf(search) > -1)
);
}
}
编辑:
我将 *ngIf="technicalRooms"
添加到 mat-form-field
上方的 div,但现在收到错误:
Cannot set property 'compareWith' of undefined
最佳答案
我按照[macjohnny] 1的指示成功解决了我的问题。 ,[GitHub 上的该问题。] 2
简而言之,问题是我需要先加载已过滤的列表,然后再将其设置在输入
中。
问题中给出的解决方案是这样的:
@Input() set data(data: any[]) {
this._data = data;
// load the initial entity list
this.filteredEntities.next(this.data.slice());
}
get data(): any[] {
return this._data;
}
private _data: any[];
但首先,我根据问题作者的想法在 Angular 中创建了一个组件,每当我需要使用它时。我将此组件称为select-search
。
完整的解决方案如下所示:
select-search.component.html
<mat-form-field *ngIf="entityFilterCtrl">
<mat-select [formControl]="entityCtrl" #singleSelect (selectionChange)="onChange($event)">
<ngx-mat-select-search
[formControl]="entityFilterCtrl"
[placeholderLabel]="'Search'"
[noEntriesFoundLabel]="'Not found'">
</ngx-mat-select-search>
<mat-option *ngFor="let entity of filteredEntities | async" [value]="entity.url">{{entity.name}}</mat-option>
</mat-select>
</mat-form-field>
select-search.component.ts
import { Component, OnInit, ViewChild, Input, EventEmitter, Output } from '@angular/core';
import { MatSelect } from '@angular/material';
import { ReplaySubject, Subject } from 'rxjs';
import { FormControl } from '@angular/forms';
import { takeUntil, take } from 'rxjs/operators';
@Component({
selector: 'app-select-search',
templateUrl: './select-search.component.html',
styleUrls: ['./select-search.component.css']
})
export class SelectSearchComponent implements OnInit {
/** control for the selected entity */
public entityCtrl: FormControl = new FormControl();
/** control for the MatSelect filter keyword */
public entityFilterCtrl: FormControl = new FormControl();
/** list of entities filtered by search keyword */
public filteredEntities: ReplaySubject<any[]> = new ReplaySubject<any[]>(1);
@ViewChild('singleSelect', { static: true }) singleSelect: MatSelect;
/** Subject that emits when the component has been destroyed. */
private _onDestroy = new Subject<void>();
@Input() set data(data: any[]) {
this._data = data;
// load the initial entity list
this.filteredEntities.next(this.data.slice());
}
get data(): any[] {
return this._data;
}
private _data: any[];
@Output() onSelectionChange: EventEmitter<any> = new EventEmitter<any>();
constructor() { }
ngOnInit(): void {
// listen for search field value changes
this.entityFilterCtrl.valueChanges
.pipe(takeUntil(this._onDestroy))
.subscribe(() => {
this.filterEntities();
});
}
ngAfterViewInit(): void {
this.setInitialValue();
}
ngOnDestroy(): void {
this._onDestroy.next();
this._onDestroy.complete();
}
onChange($event) {
this.onSelectionChange.emit($event);
}
private setInitialValue() {
this.filteredEntities
.pipe(take(1), takeUntil(this._onDestroy))
.subscribe(() => {
// setting the compareWith property to a comparison function
// triggers initializing the selection according to the initial value of
// the form control (i.e. _initializeSelection())
// this needs to be done after the filteredEntities are loaded initially
// and after the mat-option elements are available
if(this.singleSelect)
this.singleSelect.compareWith = (a: any, b: any) => a.url === b.url;
});
}
private filterEntities() {
if (!this.data) {
return;
}
// get the search keyword
let search = this.entityFilterCtrl.value;
if (!search) {
this.filteredEntities.next(this.data.slice());
return;
} else {
search = search.toLowerCase();
}
// filter the entitys
this.filteredEntities.next(
this.data.filter(entity => entity.name.toLowerCase().indexOf(search) > -1)
);
}
}
使用组件:
<app-select-search class="selectList-full-width" [data]="pokemons"></app-select-search>
[我把它放在我的 GitHub 上作为示例] 3还有[我将其导入 StackBlitz,以便我可以看到它的工作] 4 .
关于angular - 为什么 ngx-mat-select-search 在此示例中不能处理动态数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60610349/