1

I've an Observable on errors$ field in my LoginComponent:

private alerts: Array<Object>;
private errors$: Observable<IError>;
constructor()
{
    this.alerts = [];
    this.errors$ = //initialization...
}

where IError is:

export interface IError {
    code: string;
    timestamp: string;
    msg: string;
    type: string;
}

Currently, I'm creating a subscription to this Observable by hand:

this.errorsSub = this.errors$.subscribe(
    (error: IError) => {
        if (error.code != null)
            this.addAlert(error.msg);
        else
            this.clearAlerts();
    }
);

where

private addAlert(message: string): void {
    this.alerts.push({type: 'danger', msg: message});
}

private clearAlerts(): void {
    this.alerts.splice(0, this.alerts.length);
}

I'm binding alerts array in my html using an ngFor:

<div
    <alert *ngFor="let alert of alerts; let i = index" [type]="alert.type + ' alert-sm'" (close)="closeAlert(i)" dismissible="true">
        <div [innerHTML]="alert.msg"></div>
    </alert>
</div>

So, I'd like to use async pipe in order to do that. I know that's possible but I don't quite figure out how to do it... I only want to show the last notification error has been notified.

So the goal is remove alerts array.

I don't know if I've explained so well.

2 Answers 2

1

The async pipe just subscribes to the Observable and prints the latest item emitted. So in your situations you want make another Observable that will filter all items with error.code != null and use async on it.

this.errorsFiltered$ = this.errors$
    .filter(error => error.code != null)
    .share();

Then subscribe to this Observable:

<alert *ngIf="errorsFiltered$ | async" [type]="(errorsFiltered$ | async).type + ' alert-sm'"  ....>
    ...
</alert>

I'm using share() to always create only one subscription to the source Observable. However it might not be necessary depending on where the this.errors$ is coming from. If it's an HTTP request it would make multiple subscriptions without share().

Sign up to request clarification or add additional context in comments.

6 Comments

Probably, it's not related with this question. Nevertheless, I'm getting this message: TypeError: this.store$.select(...).filter is not a function. Could you help me?
Let me ask you again for another issue I don't quite figure out on yout approach. What's exactly *ngIf for? I'm guessing it's only be valid up to a first value is reached, isn't it? From a first "value" on the subscription is reached then it's going to be true, isn't it? I don't know if Ive explained so well.
The *ngIf is to make sure you're not displaying the <alert> element when there's no error. However it's true that in this you probably don't want to use the filter() operator.
When you say there's no error, what exactly do you mean? the stream is empty? when error.code == null`?
|
1

The |async pipe is use to subscribe to observables. If you push the data into an array, it's not an observable anymore:

<alert *ngFor="let alert of errors$; let i = index"

update

<alert [type]="(errors$ | async).type + ' alert-sm'" (close)="closeAlert()" dismissible="true">
    <div [innerHTML]="(errors$ | async).msg"></div>
</alert>

6 Comments

The goal i replace pushing data into an array instead of using async instead. So, the goal is remove alerts array.
You might need to use the scan() operator to collect the distinct events into an array. See also stackoverflow.com/questions/42330211/…
Why do you put them in an array, and why are you using *ngFor if you only want the last one?
I want to change it. I only want to show the last alert from now on.
Thanks @GünterZöchbauer. The next question is what about if you are using two async pipe to the same one Observable? Is it going to create two subscriptions or only one?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.