I have two components - Parent component which fetches the data from the server, and child component which is displaying fetched entries as a list - but only if the list is not null or empty.
My problem is (short): Even if there is *ngIf
checking that the list has some values, emission is done and in child component I get first emission with null
items: ![First emission] (https://i.stack.imgur.com/OHRB5.png).
Second emission is though okay... ![Secod emission] (https://i.stack.imgur.com/vK8Op.png).
Does somebody have an idea?
The parent component also contains search field where you can search entries. Here is the code:
<lookup-area [debounceTime]="100"
(searchValue)="searchChanged($event)"></lookup-area>
<app-virtual-list *ngIf="(channels$ | async)?.length > 0"
[items]="channels$ | async"
[itemHeightPx]="32"
[maxContainerHeightPx]="190 - ((channels$ | async)?.length ? 29 : 0)"
[trackByFn]="trackByFn">
<ng-template let-item>Some template</ng-template>
</app-virtual-list>
@Component({
selector: 'app-filter',
templateUrl: './filter.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
export class FilterComponent implements OnInit, OnDestroy {
public search$ = new BehaviorSubject('');
constructor(private service: YoutubeSearchService) {
}
public ngOnInit(): void {
this.channels$ = combineLatest([this.service.getYoutubeChannels(), this.search$]).pipe(
map(([channels, search]) => search ? channels.filter(channel => (channel.name || channel.id).startsWith(search)) : channels),
map(channels => channels?.sort((a, b) => (a.name || a.id).localeCompare((b.name || b.id), undefined, { sensitivity: 'base' })))
);
}
public ngOnDestroy(): void {
this.search$.complete();
}
public searchChanged(search: string): void {
this.search$.next(search);
}
public trackByFn(index: number, item: YoutubeChannel): any {
return item.id;
}
}
And the child component contains the logic for displaying. Here is the code:
@Component({
selector: 'app-virtual-list',
templateUrl: './virtual-list.html',
styleUrls: ['./virtual-list.less'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
export class VirtualList<T> implements OnChanges {
// Mandatory
@Input() public items: T[];
@Input() public itemHeightPx: number;
// Optional
@Input() public maxContainerHeightPx: number | undefined; // If undefined, scroll container's height is 100%
public ngOnChanges(changes: SimpleChanges): void {
const { items, itemHeightPx, maxContainerHeightPx } = changes;
if (this.maxContainerHeightPx && (items || itemHeightPx || maxContainerHeightPx)) {
this.setContainerScrollHeight();
}
}
}
I tried:
- wrapping everything in
<ng-container *ngIf="(channels$ | async)?.length > 0">
, but no success - wrapping in another
div
, still did not work
I have no clue what else to try because it seems that *ngIf
does not work which is really weird.
I would expect that the first change comes with the items inside since that is what *ngIf
is telling.
CodePudding user response:
Not sure I understand your issue, but I already see a bad thing in your code, so try to resolve it and see if the issue persists.
You don't need to create 3 subscriptions, a single one is enough.
<ng-container *ngIf="channels$ | async as channels">
<app-virtual-list
*ngIf="channels?.length"
[items]="channels"
[itemHeightPx]="32"
[maxContainerHeightPx]="190 - (channels?.length ? 29 : 0)"
[trackByFn]="trackByFn"
>
<ng-template let-item>Some template</ng-template>
</app-virtual-list>
</ng-container>