angularasynchronousrxjssynchronous

How to use an object in another object through subscribe angular?


I am trying to create two objects here: a user and a manager. I have the user object which has an id, and a manager which has his own unique id idManager, and an id which is from the user, OneToOne relationship between them. The backend part is working and i checked everything with postman, so it works from there. when i try to do it from frontend, for some reason the id of the user doesn't go to the idUser in the manager object. I will put the code for the createManager

createManager() {

        const formData = {
            email: this.createManagerForm.value.managerEmail,
            password: this.createManagerForm.value.managerPassword,
            role: 'MANAGER'
        };

        let idUser: string | undefined;

        this.userService.createUser(formData).subscribe({

            next: (user) => {
                idUser = user.id;

                console.log(user);

                this.createManagerForm.reset();
            },
            error: (err) => {
                // Handle error in user creation
                console.error('Error creating user:', err);
            }
        });

        console.log(idUser);

        const managerFormData = {
            name: this.createManagerForm.value.managerName,
            status: this.createManagerForm.value.managerStatus,
            user: idUser
        };

        this.managerService.createManager(managerFormData).subscribe({
            next: (manager) => {
                console.log('Manager created:', manager);
            },
            error: (err) => {
                console.error('Error creating manager:', err);
            }
        });

    }

Here are the interfaces

import {UserModel} from "./user.model";
import {EventModel} from "./event.model";

export interface ManagerModel {
  idManager: string;
  user: UserModel;
  eventList: EventModel[];
  name: string;
  status: string;
}

import {RoleModel} from "./role.model";

export interface UserModel {
  id?: string;
  email: string;
  password: string;
  role: string;
}

I know it was not ok to use the entire model instead of just a string (because im using UUID's).

In the console i get the undefined when im trying to see just the user.id, but when i try to see the user object, there the id is set.

How can i fix that?


Solution

  • Observables are asynchronous, so when we write like this, both execute separately after all the synchronous code is done, so the variable, will go as undefined, since they will be executed at any arbitary time, for this scenario, when inner API is dependent on the response of an outer API, then we can use switchMap, which will switch from an outer to inner observable, great for executing observables in sequence!

    For capturing the errors, I use catchError to console.log the error and propogate the error!

    When the API call completes I use tap to do side effects like logging something, without disturbing the observables!

    createManager() {
        let idUser: string | undefined;
        const formData = {
          email: this.createManagerForm.value.managerEmail,
          password: this.createManagerForm.value.managerPassword,
          role: 'MANAGER',
        };
    
        this.userService
          .createUser(formData)
          .pipe(
            switchMap((user: any) => { // <- changed here!
              console.log('created user');
              idUser = user.idUser;
              console.log(user);
              console.log(idUser);
              const managerFormData = {
                name: this.createManagerForm.value.managerName,
                status: this.createManagerForm.value.managerStatus,
                user: { id: idUser }, // backend requires like this structure to be passed!
              };
              return this.managerService.createManager(managerFormData).pipe(
                tap(() => console.log('created manager')),
                catchError((err: any) => {
                  console.error('Error creating user:', err);
                  return throwError(err);
                })
              );
            }),
            catchError((err: any) => {
              console.error('Error creating manager:', err);
              return throwError(err);
            })
          )
          .subscribe(() => {
              this.createManagerForm.reset();
              console.log('all done!!!')); // <- notice!
         });
      }