Return Observable<boolean> from service method after two subscriptions resolve

31,294

Solution 1

As noticed from other answer by @user184994, forkJoin won't work in this case. Instead you can use combineLatest, and then very similarily like @user184994 have otherwise implemented the service code:

isProfileOwner(): Observable<boolean> {
  return Observable.combineLatest(this.currentUser, this.profileId$)
    .map(results => {
       let user = results[0];
       let profile = results[1];
       return (user.username === profile)
    });
}

DEMO

Solution 2

This can be achieved through Subject

import { Subject } from 'rxjs';

public isProfileOwner(): Observable<boolean> {
        var subject = new Subject<boolean>();

        this.currentUser.subscribe(user => {
                this.profileId$.subscribe(
                    profile => {
                        console.log(profile + ' ' + user.username); // match!
                        if (profile === user.username) {
                            subject.next(true);
                        } else {
                            subject.next(false);

                        }
                    }
                )
            })
            return subject.asObservable();
    }

Solution 3

I would personally suggest using forkJoin, to wait for the observables, and flatMap to convert to an Observable<boolean>

return Observable.forkJoin(this.currentUser, this.profileId$).flatMap(
    results => {
        user = results[0];
        profile = results[1];
        return Observable.of(profile === user.username)
    }
);
Share:
31,294
Ben Racicot
Author by

Ben Racicot

I'm a software engineer.

Updated on July 05, 2022

Comments

  • Ben Racicot
    Ben Racicot almost 2 years

    I'm trying to setup a simple way to compare the current username with a profile's username within an Angular service.

    Obviously the profile username and the user's username must resolve before I can compare them so how do I return a boolean observable so that I can subscribe to this comparison within components?

    This is where I'm at:

    public profileId = new Subject<string>; // Observable string source updated from a profile.component (when the URL displays the profile's username)
    public profileId$ = this.profileId.asObservable();
    public currentUser = this.principal.asObservable().distinctUntilChanged();
    
    public isProfileOwner(): Observable<boolean> { // A function whose declared type is neither 'void' nor 'any' must return a value.
        this.currentUser.subscribe(user => {
                this.profileId$.subscribe(
                    profile => {
                        console.log(profile + ' ' + user.username); // match!
                        if (profile === user.username) {
                            return Observable.of(true);
                        } else {
                            return Observable.of(false);
                        }
                    }
                )
            })
    }
    

    This seems to be the way other SO answers explain to do it but I'm getting [ts] A function whose declared type is neither 'void' nor 'any' must return a value.

    I'd like to subscribe to test within components.

    this.authService.isProfileOwner().subscribe(
        data => {
            console.log(data); // should be boolean
        }
    )
    
  • Ben Racicot
    Ben Racicot over 6 years
    great answer. Can explain how I should be subscribing to this boolean? (getting blank results)
  • user184994
    user184994 over 6 years
    What do you mean by "blank results"?
  • Ben Racicot
    Ben Racicot over 6 years
    I've updated the question to show my subscribe code. logging the result shows nothing.
  • user184994
    user184994 over 6 years
    As in, the log message is never printed?
  • Ben Racicot
    Ben Racicot over 6 years
    Yes, nothing is printed.
  • David Bulté
    David Bulté over 6 years
    Nice. But I think you can use map() iso flatmap()?
  • Ben Racicot
    Ben Racicot over 6 years
    @DavidBulté awesome. Care to write up an answer? Having trouble rounding third on this.
  • Ben Racicot
    Ben Racicot over 6 years
    @user184994 turns out forkJoin only works on raw Observable types. asObservable , Subject, etc will not work.
  • Ben Racicot
    Ben Racicot over 6 years
    this is awesome, I've updated the question! I noticed that it doesn't work for me because my initial profileId is a Subject source. I need this to be a subject (I think) so that profile.component can update it with the actual profile username. then becomes a stream with: profileId$ = this.profileId.asObservable();
  • AT82
    AT82 over 6 years
    Well the difference between a Subject and a BehaviorSubject is basically that Subject requires next for subscription to fire. Not knowing your complete use case, but I don't see why you couldn't have it as an BehaviorSubject with initial value of null or something and then do a null check? Is that a possibility for you to do?
  • Ben Racicot
    Ben Racicot over 6 years
    Thank you for patience, I was updating the BehaviorSubject wrong. Great answer to a complex question.
  • AT82
    AT82 over 6 years
    No problem, glad I could help! user184994 did a good job as well, just needed some minor tweaks to make it work, so glad we got you a solution! :)