I have the following pipeline and html template, but the app always displays #noMatch
and doesn't logs "in the pipe"
in the reduce
function. I feel it's a matter of timing but I'm not able to fix it.
ts
user$: Observable<User> = new Observable<User>();
matches$: Observable<User[]> = this.user$.pipe(
switchMap((user: User) => {
this.type= user.type;
return of([user, user, user]);
}),
distinctUntilChanged(),
);
filteredMatches$: Observable<{ type1: User[]; type2: User[] }>;
ngOnInit(): void {
this.user$ = this.authService.user$;
this.filteredMatches$ = this.matches$.pipe(
reduce((acc: any, curr: User[]) => {
if (!acc.type1) acc.type1= [];
if (!acc.type2) acc.type2= [];
console.log('in the pipe');
this.networkingService.decideType(this.type, curr.type)
? acc.type1.push(curr)
: acc.type2.push(curr);
return acc;
}),
);
}
html
<ng-template *ngIf="(filteredMatches$ | async) as matches; else noMatch">
<app-child *ngFor="let user of matches.type1" [user]="user">
<app-child *ngFor="let user of matches.type2" [user]="user">
</ng-template>
<ng-template #noMatch>
<app-no-match></app-no-match>
</ng-template>
CodePudding user response:
Ah found it. You do this:
user$: Observable<User> = new Observable<User>();
matches$: Observable<User[]> = this.user$.pipe(
switchMap((user: User) => {
this.type= user.type;
return of([user, user, user]);
}),
distinctUntilChanged(),
);
mathes$
listens to user$
which is a new Observable.
Then, on ngInit you do this:
this.user$ = this.authService.user$;
You replace the value of user$ with the authService's user$. But mathes$ is still subscribed to the first Observable, which is not doing anything.
I suggest you replace
user$: Observable<User> = new Observable<User>();
//by
user$: Observable<User> = this.authService.user$;
Or better yet, directly use the authService's user$ instead of creating a property for it.
EDIT: In my opinion, there is no reason to use the ngOnInit here, you could simply have the observable set at the beggining...
matches$: Observable<User[]> = this.authService.user$.pipe(
switchMap((user: User) => {
this.type= user.type;
return of([user, user, user]);
}),
distinctUntilChanged(),
);
filteredMatches$: Observable<{ type1: User[]; type2: User[] }> = this.matches$.pipe(
reduce((acc: any, curr: User[]) => {
if (!acc.type1) acc.type1= [];
if (!acc.type2) acc.type2= [];
console.log('in the pipe');
this.networkingService.decideType(this.type, curr.type)
? acc.type1.push(curr)
: acc.type2.push(curr);
return acc;
}),
);
CodePudding user response:
@Salketer's answer is correct - the reason and the solution. Further: if, for some reason or another, the source observable isn't available yet in the constructor (it depends on some inputs, for example), you could do something like this
user$: Observable<User> = new Subject<User>();
matches$: Observable<User[]> // no changes here
ngOnInit(): void {
this.authService.user$.subscribe(this.users$);
(A Subject
is both an observable and an observer).