Я создал многоразовый компонент ngx-mat-select-search, который выглядит так
mat-tooltip-select-all.comComponent.ts
export class MatTooltipSelectAllComponent implements OnInit, AfterViewInit, OnDestroy {
@Input() placeHolderName: string;
@Input() isDate: boolean = false;
/** emit an event when a new option is selected */
@Output() newOptionSelected = new EventEmitter<SelectOption[]>();
/** control for the selected option for multi-selection */
public multiCtrl: FormControl<SelectOption[]> = new FormControl<SelectOption[]>([]);
/** control for the MatSelect filter keyword multi-selection */
public multiFilterCtrl: FormControl<string> = new FormControl<string>('');
/** list of selectOptions filtered by search keyword */
public filteredMulti: ReplaySubject<SelectOption[]> = new ReplaySubject<SelectOption[]>(1);
public tooltipMessage = 'Select All / Unselect All';
@ViewChild('multiSelect', { static: true }) multiSelect: MatSelect;
/** Subject that emits when the component has been destroyed. */
protected _onDestroy = new Subject<void>();
@Input() set selectOptions(selectOptions: SelectOption[]) {
this._selectOptions = selectOptions;
// load the initial option list
this.filteredMulti.next(this.selectOptions.slice());
}
get selectOptions(): SelectOption[] {
return this._selectOptions;
}
private _selectOptions: SelectOption[];
constructor() { }
ngOnInit() {
// set initial selection to all
// this.multiCtrl.setValue(this._selectOptions.slice());
// listen for select option value changes
this.multiCtrl.valueChanges
.pipe(takeUntil(this._onDestroy))
.subscribe(() => {
this.newOptionSelected.emit(this.multiCtrl.value);
});
// listen for search field value changes
this.multiFilterCtrl.valueChanges
.pipe(takeUntil(this._onDestroy))
.subscribe(() => {
this.filterMulti();
});
}
Я использую его несколько раз для родительского компонента, но по какой-то причине данные загружаются только в первом экземпляре ngx-mat-select-search. Например
//pdoNames is loaded
<app-mat-tooltip-select-all
#pdoNameFilter
class = "col-md-6"
(newOptionSelected) = "handleFilter($event, Filter.PDOName)"
[selectOptions] = "pdoNames"
placeHolderName = "PDO Name"
></app-mat-tooltip-select-all>
//beneficiaryClassifications is not loaded/filtered list is empty
<app-mat-tooltip-select-all
#beneficiaryFilter
class = "col-md-6"
(newOptionSelected) = "handleFilter($event, Filter.BeneficiaryClassification)"
[selectOptions] = "beneficiaryClassifications"
placeHolderName = "Beneficiary Classification"
></app-mat-tooltip-select-all>
Данные извлекаются в родительском компоненте следующим образом
родительский компонент ts
ngOnInit(): void {
this.reportService
.getFundingNeedsSummary()
.pipe(take(1))
.subscribe((response: any) => {
// sets pdoNames and beneficiaryClassifications here
});
}
Мне нужно проверить длину параметра, например *ngIf="beneficiaryClassifications?.length > 0" в последующих экземплярах, чтобы он работал. Но проблема этого подхода в том, что компонент не будет отображаться, если длина параметра пуста или равна 0.
Как я могу заставить это работать без проверки длины параметра или заставить компонент отображаться, даже если длина параметра равна 0? Я пробовал использовать *ngIf = "beneficiaryClassifications?.length == 0 || beneficiaryClassifications?.length > 0", но он не загружает данные/параметры фильтра становятся пустыми.
Полный воспроизводимый код: https://stackblitz.com/edit/github-qartsv?file=src%2Fapp%2Fapp.comComponent.html
@NarenMurali добавил ссылку на Stackblitz, извините за задержку, мне потребовалось некоторое время, чтобы настроить и воспроизвести код в stackblitz.





Попробуйте использовать OnChanges, чтобы обнаружить изменения в дочернем компоненте.
https://angular.io/api/core/OnChanges
Также попробуйте установить ng-модель с двусторонней привязкой, чтобы убедиться, что вы получаете каждое изменение данных.
Я не думаю, что мне нужна двусторонняя привязка данных. Единственная цель дочернего компонента app-mat-tooltip-select-all — получить список selectOptions от родительского компонента и вернуть выбранные параметры в (newOptionSelected) = "handleFilter($event, Filter.BeneficiaryClassification)".
Нам нужно обновить ссылку на массив, когда мы выполняем операцию push, поскольку содержимое изменяется, но местоположение памяти остается прежним.
Angular считает, что ничего не изменилось, поэтому вы не можете просмотреть список, только выполняя операцию push.
Когда мы выполняем деструктуризацию массива (this.clientType = [...this.clientType]), у массива появляется новая ссылка на память, поэтому angular запускает обнаружение изменений по @Input и делает список видимым.
populateFilters() {
this.tableData.forEach((pdo) => {
const clientType = {
id: pdo?.client_type ? pdo?.client_type.id : 'null',
name: pdo?.client_type ? pdo?.client_type.name : 'null',
};
if (!this.isExisting(clientType, this.clientType)) {
this.clientType.push(clientType);
}
});
this.clientType = [...this.clientType]; // <- changed here!
}
Я заметил, что фильтры, заполненные с помощью Array.push(), не заполняются. Но я не знал почему, спасибо за объяснение.
пожалуйста, поделитесь полным воспроизводимым кодом, если возможно, стекблицом, где возникает проблема!