Search code examples
angularmodelnormalizationangular-httpclient

Angular API requests for models with relationships to other models on id


Let's say I have arrays as below:

Students = [
  {
    id: 1,
    name: "Sara",
    schoolId: 1,
    carId: 3,
  },
  {
    id: 2,
    ...
  },
]

School = [
  {
    id: 1,
    name: "Some college",
    location: "Somewhere",
  },
  {
    id: 2,
    ...
  },
]

Car = [
  {
    id: 3,
    make: "",
    model: ""
  }
]

API Service:

getStudents() {
  return this.http.get<Student[]>(this.studentUrl);
}

As I am to do a GET request to Students like above, I would only get the ids: schoolId and carId. What is the proper way to link these two properties to the actual object from the other two object lists so that the result from getStudents() would return something like below and be able to call student.schoolId.name in the HTML?

{
    id: 1,
    name: "Sara",
    schoolId: {
      id: 1,
      name: "Some college",
      location: "Somewhere",
    },
    carId: {
      id: 3,
      make: "",
      model: ""
    }
}

I've looked into mapping and flatmap but I was not sure if this was the way to go. I am basing these objects on what the database data would send. The schoolId and carId columns contain the id that link the id from the School and Car table.


Solution

  • Either you work in the back-end service to return the data with the associated entity(s) as mentioned in the comment, or you can work with forkJoin to send responses to grab multiple data. After the observables are completed, use the map to transform data as below:

    export interface Student {
      id: number;
      name: string;
      schoolId: number;
      carId: number;
    }
    
    export interface School {
      id: number;
      name: string;
      location: string;
    }
    
    export interface Car {
      id: number;
      make: string;
      model: string;
    }
    
    export interface StudentWithSchoolCarData extends Student {
      school: School;
      car: Car;
    }
    
    getStudentsWithSchoolCarData(): Observable<StudentWithSchoolCarData[]> {
      return forkJoin([
        this.http.get<Student[]>(this.studentUrl),
        this.http.get<School[]>(this.schoolUrl),
        this.http.get<Car[]>(this.carUrl),
      ]).pipe(
        map(([students, schools, cars]: any[]) => {
          return students.map((x: Student) => ({
            ...x,
            school: schools.find((y: School) => y.id == x.schoolId),
            car: cars.find((y: Car) => y.id == x.carId),
          }));
        })
      );
    }
    

    Demo @ StackBlitz