Angular RxJS: два вложенных https и компонент обновления при достижении первого - PullRequest
0 голосов
/ 23 мая 2019

Мне нужно выполнить два http-запроса.Один за первым, поскольку значения, предоставленные первым, будут использоваться для выполнения других вызовов http.

Мне также необходимо обновить мой компонент при разрешении первого http также обновил его, когда второй http также разрешен .

interface Vehicle {
    readonly id: string;
    readonly name: string;
    readonly brand: string;
}

Первый вызов http получает name, а другой brand.

Угадай этот HTML-компонент:

<div *ngFor='let vehicle of vehicles$ | async'>
    {{vehicle.name}} - {{vehicle.brand}}
</div>

В контроллере:

vehicles$: Observable<Array<Vehicle>>
ngOnInit() {
    this.vehicles$ = this._vehicleService.getVehicles();
    // how to go on???
}

где getVehicles:

getVehicles(): Observable<Array<Vehicle>> {
    return http.get("url")
        .map(vehicle => <Vehicle>{id: vehicle.id, name: vehicle.name});
}

getVehicleBrand(ids: Array<String>): Observable<Array<VehicleBrand>> {
   // build url according ids parameter
   return http.get("url")
       .map(brand => <VehicleBrand>{id: brand.vehicle_id, brand.name});
}

Как я могу объединить Vehicle с VehicleBrand

Ответы [ 4 ]

1 голос
/ 23 мая 2019

Слияние данных между запросами не должно быть обязанностью компонента. Для этого и нужны услуги.

Пример того, как может выглядеть такой сервис (конечно, вы можете настроить его в соответствии с вашими потребностями):

const vehiclesIdNameMock: VehicleIdName[] = [
  { id: 'vehicle-1', name: 'Vehicle 1' },
  { id: 'vehicle-2', name: 'Vehicle 2' },
  { id: 'vehicle-3', name: 'Vehicle 3' },
];

const vehiclesIdToBrandMap: { [key: string]: VehicleIdBrand } = {
  'vehicle-1': { id: 'vehicle-1', brand: 'Brand A' },
  'vehicle-2': { id: 'vehicle-2', brand: 'Brand A' },
  'vehicle-3': { id: 'vehicle-3', brand: 'Brand B' },
}

@Injectable()
export class VehiclesService {
  private getVehiclesIdName(): Observable<VehicleIdName[]> {
    return of(vehiclesIdNameMock).pipe(delay(500));
  }

  private getVehicleIdBrand(id: string): Observable<VehicleIdBrand> {
    return of(vehiclesIdToBrandMap[id]).pipe(delay(500));
  }

  public getVehicles(): Observable<Vehicle[]>{
    return this.getVehiclesIdName().pipe(
      mergeMap(vehiclesIdName => {
        const requests: Observable<VehicleIdBrand>[] = vehiclesIdName.map(vehicleIdName => this.getVehicleIdBrand(vehicleIdName.id))

        return forkJoin(requests).pipe(
          map(vehiclesIdBrand => vehiclesIdBrand.map(
            (vehiclesIdBrand, index) => ({ ...vehiclesIdBrand, ...vehiclesIdName[index] })
          ))
        );
      })
    )
  }
}

Два приватных метода здесь являются ложными, потому что у меня, очевидно, нет доступа к вашей конечной точке, но пока вы возвращаете тот же тип данных, который будет в порядке.

Тогда ваш VehicleComponent будет таким же чистым, как:

@Component({
  selector: 'app-vehicles',
  templateUrl: './vehicles.component.html',
  styleUrls: ['./vehicles.component.css']
})
export class VehiclesComponent {
  public vehicles$: Observable<Vehicle[]> = this.vehiclesService.getVehicles();

  constructor(private vehiclesService: VehiclesService) {}
}

Вот живая демонстрация на Stackblitz https://stackblitz.com/edit/angular-et3oug

0 голосов
/ 23 мая 2019

Вы можете использовать async await, вот пример.

Контроллер

vehicles$: Observable<Array<Vehicle>>
ngOnInit() {
      this.getVehicle(); 
}

async getVehicle() {
    this.vehicles$ = this._vehicleService.getVehicles(["1", "2"]);
    await getVehicleBrand([vehicalIds]);
    // other code
}

getVehicleBrand(ids: Array<String>): Observable<Array<VehicleBrand>> {
return new Promise(resolve => { 
   // build url according ids parameter
   http.get("url")
       .map(brand => <VehicleBrand>{id: brand.vehicle_id, brand.name});
    resolve();
  })
}
0 голосов
/ 23 мая 2019

Если вы хотите возвращать наблюдаемые последовательно, вы можете использовать mergeMap RxJS для отображения наблюдаемых значений из getVehicles() службы во внутреннюю наблюдаемую, чтобы получить список идентификаторов.,Затем мы вызываем метод getVehicleBrand() из службы, и наблюдаемые значения возвращаются в subscribe () в следующей строке.

Оттуда вы можете сопоставить название бренда с соответствующими транспортными средствами.

На ваших component.ts, вот как это будет выглядеть

ngOnInit() {
  this._vehicleService.getVehicles(["1", "2"]).pipe(
    mergeMap(vehicles => {
      const vehicleIdList: string[] = vehicles.map(vehicle => vehicle.id);
      return this._vehicleService.getVehicleBrand(vehicleIdList);
    })
  ).subscribe(res => {
    // continue the rest
  })
}
0 голосов
/ 23 мая 2019

Вы можете сделать что-то вроде этого:

http.get("url").pipe(
    map(vehicle => <Vehicle>{id: vehicle.id, name: vehicle.name})
    tap(vehicle => { this.vehicles$.next(vehicle); })
    switchMap(vehicle => this.getVehicleBrand([vehicle.id]));
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...