3

I have the following inside of a Component's template:

<span>
  {{(userService.CurrentUser | async)?.FullName }}
</span>

userService.CurrentUser is an Observable that generates objects of type User. User has propreties named FirstName, LastName, FullName, etc.

This code works fine as it stands. I'm now trying to customize what is displayed when at different screen sizes. I've modified the template as follows:

<!--  At screen size sm , show the user's first name  -->
<span class="d-none d-sm-inline d-md-none">
  {{(userService.CurrentUser | async)?.FirstName }}
</span>

<!--  At screen size md or larger, display user's full name  -->
<span class="d-none d-md-inline">
  {{(userService.CurrentUser | async)?.FullName }}
</span>

Unfortunately, this doesn't work as expected. A little experimentation seems to indicate that whichever one of the two <span> elements comes first in the template's markup will have its expression evaluated, while the second one won't, leading it to have no content.

If I bind to a property within the component instead of using the async pipe to bind to an Observable, I don't have this problem.

While I could keep track of the current value of the Observable by subscribing to it within my component and maintaining my own copy of the most recent value of the Observable, this seems to be rewriting the async pipe.

I also see in angular - using async pipe on observable<Object> and bind it to local variable in html that I could get the most recent observable value stored into a variable by using an *ngIf.

Why does what I have not work as expected? I'd like to understand before going with one of the two alternatives above.

Update: Here's the code I'm using the set up the CurrentUser Observable. Based on a comment, I think this is the source of the problem. I suspect that it's the fact that I'm only keeping track of a single subscriber in the function passed to the Observable constructor. I don't think I understand the proper way to create an Observable and then notify Observers.

export class UserService {
  private currentUser : User;
  private currentUserObservable : Observable<User>;
  private currentUserObserver : Observer<User>;

  constructor()  {
    this.currentUserObservable = new Observable<User>(
      observer => {
        this.currentUserObserver = observer;
      }
    );
  }

  get CurrentUser() : Observable<User> {
    return this.currentUserObservable;
  }

  login (emailAddress : string, password : string) : void {
    this.currentUser = new User(emailAddress, "username", "First Name", "Last Name");      
    this.currentUserObserver.next(this.currentUser);
  }
}
6
  • Have you tried to use the share() operator? You can set a property in your class to this.user$ = userService.CurrentUser.share() and then use that property in your template (user$ | async). If that works I'll write up about it in an answer. Commented Mar 16, 2018 at 19:20
  • Can we see your CurrentUser observable? Commented Mar 16, 2018 at 19:21
  • Using Single Subscription for Multiple Async Pipes: nitayneeman.com/posts/… Commented Mar 16, 2018 at 19:43
  • Possible duplicate of angular - using async pipe on observable<Object> and bind it to local variable in html Commented Mar 16, 2018 at 21:28
  • @ConnorsFan I've updated it to include the code which provides the Observable, and I think that implementation is likely the problem. As I stated in the edit, I think the problem lies in my understanding of Observables. Commented Mar 19, 2018 at 14:06

1 Answer 1

3

It should work as it is. However there are several inefficiencies as the documentation points out: Storing conditional result in a variable (Show a set of properties from the same object)

You could try:

<ng-container *ngIf="userService.CurrentUser | async as user">

  <!--  At screen size sm , show the user's first name  -->
  <span class="d-none d-sm-inline d-md-none">
    {{ user.FirstName }}
  </span>

  <!--  At screen size md or larger, display user's full name  -->
  <span class="d-none d-md-inline">
    {{ user.FullName }}
  </span>

</ng-container>

There is only one suscription and it is much cleaner.

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

1 Comment

Thanks, but I understand the inefficiencies and saw the approach of using the ng-if to bind to a local variable already. I was hoping to understand why the approach I specified didn't work correctly. I think my Observable implementation is the problem; see some of my responses to the comments above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.