Search code examples
angulartypescriptdto

How do I transform backend data with async fields in angular?


In my angular application, I have to transform some data from backend API. The problem is that some fields need to be assigned with data from the server either.

For example, I have a client (it's a simplified example):

{
  id: 1122,
  firstname: 'John',
  lastname: 'Doe',
  countryId: 12
}

There is a country ID. I want to get country name from the server by the ID.

I have used asynchronous angular pipes in template that returns Observable with country name string:

<h3>{{ client.countryId | countryAsyncPipe | async}}</h3>

But I need data not only in the templates.

So, how do I resolve this kind of a problem?

Thank you!

UPDATE:

I'm sorry, I haven't provided enough information in the question. I will try to explain what I mean with some hypothetic example.

First of all, I.ve forgot to say that I'm trying to create DTO. I've got an API Service, for instance, ClientHttpService:

@Service()
class ClientHttpService extends Http {

  findAll(): Observable<Array<Client>> {
    return this.get(this.url).pipe(
        map(client => clientSerializer.fromJsonFactory(client))
      );
  }
}

I receive JSON clients and create instances of ClientModel (not necessary, it may be a literal object) with serializer service:

class Client extends Model {
  id: number;
  firstname: string;
  lastname: string;
  countryName: string;

  constructor({ id, firstname, lastname, countryName }) {
    //...set object properties
  }
}

@Service()
class ClientSerializer implements Serializer {

  public fromJson(data: any): Client {
    return new Client({
      id: data.id,
      firstname: data.firstname,
      lastname: data.lastname,
      countryName: data.countryId // trouble
    });
  }

  public fromJsonFactory(data: Array<any>): Array<Client> {
    return data.map(client => this.fromJson(client));
  }
}

Well, here is a problem. I really don't understand how to provide the country name. Let's say, I've got CountryService:

@Service()
class CountryHttpService extends Http {

  findNameById(id: number): Observable<string> {
    return this.get(`countryUrl`).pipe(map(country => country.name));
  }
}

How could I correctly provide result into my Serializer if it returns Observable?

return new Client({
  //...
  countryName: countryService.findNameById(data.countryId) // Observable, not string
});

Solution

  • You need to subscribe() or toPromise().then() in order to get the desired data within your .ts file. For example, let's say you have a CountryService with a method

    getCountryName(countryId: number): Observable<string> {
       return this.http.get<string>(your endpoint);
    }
    

    In the component that you want to fetch the countryName you should inject your service and:

    this.countryService .getCountryName(countryId).toPromise().then( (countryName: string) => {
       // transform your data here
    });
    

    or replace toPromise().then() with subscribe().

    UPDATE:

     public fromJson(data: any): Client {
        this.countryService.findNameById(data.countryId).subscribe((countryName: string) => {
            return new Client({
               id: data.id,
               firstname: data.firstname,
               lastname: data.lastname,
               countryName: countryName
            });
        });
       return null;
     }