I need to create a mechanism that opens inside a Popup Window and notifies the parent page, and emits the event as a Promise.
parentponent.ts
.....
private async instance(): Promise<void> {
if (this.exist())
await this.getSSO();
}
private async getSSO(): Promise<void> {
const currentClientID = this.getClientID();
this.loading = true;
await this.ssoService.call().pipe(
finalize(() => {
this.loadingSSO = false;
})
).toPromise().then(result => {
if (result?.clientId === currentClientID) {
return result;
}
});
}
.....
sso.service.ts
ssoEvent = new Subject<any>();
public call(): Observable<any> {
const urlPage = this.getUrl();
const ssoPagina = window.open(urlPage);
window.addEventListener("message", this.handleMessage.bind(this), false);
return this.ssoEvent.pipe(
take(1),
);
}
protected handleMessage(event: MessageEvent): void {
if (event.origin !== window.location.origin) {
return;
}
if (event.data?.success) {
this.ssoEvent.next(event.data?.result);
}
}
I need to create a filter that if the clientID received via postmessage is not the same as the clientID of the parent component, the propagation of the event is blocked until the correct clientid is received, is this possible?
I tried using operators like 'filter', 'map' and other rxjs operators
await this.ssoService.call().pipe(
filter(result => result?.clientId === clientID),
finalize(() => {
this.loadingSSO = false;
})).toPromise()
Both observable filtering solutions, with 1 of the 2 concurrent executions issuing await of ok to all instance methods twice
I need to create a mechanism that opens inside a Popup Window and notifies the parent page, and emits the event as a Promise.
parentponent.ts
.....
private async instance(): Promise<void> {
if (this.exist())
await this.getSSO();
}
private async getSSO(): Promise<void> {
const currentClientID = this.getClientID();
this.loading = true;
await this.ssoService.call().pipe(
finalize(() => {
this.loadingSSO = false;
})
).toPromise().then(result => {
if (result?.clientId === currentClientID) {
return result;
}
});
}
.....
sso.service.ts
ssoEvent = new Subject<any>();
public call(): Observable<any> {
const urlPage = this.getUrl();
const ssoPagina = window.open(urlPage);
window.addEventListener("message", this.handleMessage.bind(this), false);
return this.ssoEvent.pipe(
take(1),
);
}
protected handleMessage(event: MessageEvent): void {
if (event.origin !== window.location.origin) {
return;
}
if (event.data?.success) {
this.ssoEvent.next(event.data?.result);
}
}
I need to create a filter that if the clientID received via postmessage is not the same as the clientID of the parent component, the propagation of the event is blocked until the correct clientid is received, is this possible?
I tried using operators like 'filter', 'map' and other rxjs operators
await this.ssoService.call().pipe(
filter(result => result?.clientId === clientID),
finalize(() => {
this.loadingSSO = false;
})).toPromise()
Both observable filtering solutions, with 1 of the 2 concurrent executions issuing await of ok to all instance methods twice
Share Improve this question asked Feb 17 at 20:44 fixesMyCodefixesMyCode 112 bronze badges New contributor fixesMyCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.1 Answer
Reset to default 0You could make use of lastValueFrom
/firstValueFrom
depending on your needs, along with EMPTY
and high order observables (concatMap
, switchMap
, mergeMap
, exhaustMap
)
toPromise
will be deprecated in rxjs v8. You can read more about it here
lastValueFrom
converts an observable to a promise by subscribing to the observable, waiting for it to complete, and resolving the returned promise with the last value from the observed stream.
firstValueFrom
converts an observable to a promise by subscribing to the observable, and returning a promise that will resolve as soon as the first value arrives from the observable. The subscription will then be closed.
For example:
@Component({...})
export class Foo implements OnInit {
call$ = of({ clientId: 55 }).pipe(delay(1500)); // "API" dummy call
myClientId = 22;
loadingSSO = true;
async ngOnInit(): Promise<void> {
const response$ = this.call$.pipe(
concatMap((response) => {
// only if both ids are equal then return an observable with TRUE
if (response.clientId === this.myClientId) {
this.loadingSSO = false;
return of(true);
}
return EMPTY; // emits no value
})
)
const areIdsEqual = await firstValueFrom(response$);
console.log('Both ids are equal?', areIdsEqual);
}
}
For this scenario, I am using concatMap
because I want to wait for the API response, and only when I get the response then I proceed to handle the logic, so I am "concatenating" observables.
You will not see an output in the console since myClientId !== clientId
, but if both are equal, then a value gets emitted and you will see a log in the console as Both ids are equal? true
Try the demo and see what happens when the id's are equal.