0

There is a getUser function in the UserDataService service, in which I call the tokens function, get a token and pass it to another getUser function, from which I get a user by his id.

getUser(id: number) {
  return this.sharedDataService.tokens.subscribe((result) => {
    return this.userService
      .getUser(result, id)
      .subscribe((resultService: DataResponse<User>) => {
        if (resultService.status === StatusType.SUCCESSFUL) {
          return resultService.data;
        } else {
          return null;
        }
      });
  });
}
export interface User{
  id: number;
  name: string;
}

How do I get a User object when calling this function? This code will not work.

let user = this.userDataService.getUser(1);

How to correctly pass objects from such functions? You can transmit by event, but in this case it is not very convenient. Maybe you can subscribe to the get User function?

alex
  • 324
  • 1
  • 8
  • 28

2 Answers2

2

In similar cases, it's recommended to return the Observable itself (instead of subscribing to it within the service), and then subscribe to it within the components.

You can try the following:

import { map, switchMap } from 'rxjs/operators';

getUser(id: number): Observable<User | null> {
  return this.sharedDataService.tokens.pipe(
    switchMap((result) => this.userService.getUser(result, id)),
    map((resultService: DataResponse<User>) => {
      if (resultService.status === StatusType.SUCCESSFUL) {
        return resultService.data;
      } else {
        return null;
      }
    })
  );
}

And within the component class, you can get the user object like the following:

this.userDataService.getUser(1).subscribe((user) => {
  // You can use the `user` here...
  console.log(user);
});

Or you can assign the getUser result to a new Observable in the component class, then use it (subscribe to it) in the component template using async pipe, like the following:

// Component class:
user$: Observable<User>;

ngOnInit(): void {
  this.user$ = this.userDataService.getUser(1);
}
<!-- Component template -->
<div *ngIf="user$ | async as user">
  <!-- You can use `user` object here -->
  <span>{{ user.name }}</span>
</div>
Amer
  • 6,162
  • 2
  • 8
  • 34
  • In this code I get an error: The 'null' type cannot be assigned to the 'User' type. – alex Feb 06 '22 at 14:24
  • 1
    @alex sorry, my bad. you just need to use `Observable` as a return type of `getUser` function, instead of `Observable`. – Amer Feb 06 '22 at 15:10
1

It depends on your code, but I guess you should do something like this:

import { switchMap, map, tap } from 'rxjs/operators';
... 
getUser(id: number) {

   return this.sharedDataService.tokens
   .pipe(
      switchMap(token => this.userService.getUser(token, id)),
      tap(
         (resultService: DataResponse<User>) => {

            if (resultService.status === StatusType.SUCCESSFUL) {
              return resultService.data;
            } else {
              return null;
            }

      }),
    );

You also can type your function, depending on what resultService.data type is.

For instance, if resultService.data is User type, you can type your function as:

getUser(id: number): Observable<User|null> {
  • 1
    This won't work! returning a value from the `subscribe` method, won't affect the returned value from the `getUser` function itself. – Amer Feb 05 '22 at 11:25
  • I don't know where my head was! (facepalm) Of course it wouldn't work, it was a classic rookie mistake! I wasn't awake when I answer the question :) Now I've just edited it, @Amer, thanks for pointing out the error! – Juan Vicente Berzosa Tejero Feb 05 '22 at 12:05
  • Sorry @Amer, I hadn't seen your reply, where you basically corrected the same thing I've just edited! Now that I look at it more closely, you use **map** and I use a **tap**, but I think the result would be the same, right? – Juan Vicente Berzosa Tejero Feb 05 '22 at 12:10
  • No, it won't be the same result. Using `tap` doesn't transform the data, and the returned value of the `Observable` will be the type of `this.userService.getUser(token, id)` switched using `switchMap`. However, using `map` will transform the `Observable` type to the new type returned from `map`. Check this please: https://stackoverflow.com/questions/61295224/what-is-the-difference-between-tap-and-map-in-rxjs/61295611 – Amer Feb 06 '22 at 15:20