Angular 2 наблюдаемый Как извлечь ответ?

import { Injectable }     from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Rx';

// Import RxJs required methods
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch'

@Injectable()
export class EquipmentService{
    data: any;
    constructor(private http:Http){

    }
    getDefaultEquipment(){
        this.http.get('./app/SaveData/equipmentTest.json')
            .map((res:Response) => res.json())
            .subscribe(data => { this.data = data},
                err => console.error(err),
                () => console.log(this.data));
    }
}

Чтение данных из файла. Важным битом является getDefaultEquipment().

Если вы видите последний console.log(this.data), то данные верны, это именно то, что мне нужно. Но если я return this.http.get(... () => {return this.data}), я получаю неопределенность. Как мне получить и вернуть this.data??

Очевидно, что если я напишу еще один возврат, такой как следующий, наблюдаемый объект еще не завершен, поэтому он вернет пустые данные: any.

//clearly won't work because the get hasn't returned yet
getDefaultEquipment(){
    this.http.get(...data => {this.data = data}...);
    return this.data;
}

person nathan rogers    schedule 22.11.2016    source источник
comment
Просто верните наблюдаемое. вам не нужно преобразовывать асинхронный вызов в синхронный вызов.   -  person Cleiton    schedule 23.11.2016
comment
Вы не можете вернуть данные. Не подписывайтесь. Просто верните наблюдаемое. Вызывающий будет тем, кто подпишется, и получит данные в функции обратного вызова, переданной в subscribe().   -  person JB Nizet    schedule 23.11.2016
comment
Потрясающий. Это помогло. Добавлен метод подписки для вызывающей стороны в моем компоненте оборудования this.equipmentService.getDefaultEquipment().subscribe( stuff => {console.log(stuff)}, ); Спасибо.   -  person nathan rogers    schedule 23.11.2016


Ответы (1)


Следующее будет моим взглядом на это. Непроверенный, но концепция твердая. Это сэкономит вам много шаблонного кода из-за канала async, который в основном съедает Observables. Если вам нужно выполнить некоторые преобразования, это будет возможно также до возврата наблюдаемого. Вы можете сделать это либо в сервисе, либо в компоненте. Просто помните, что касается Observables, обязательно используйте оператор .share(), если у вас несколько подписчиков, иначе вы бы выполнили (в данном случае) http.get один раз для каждого подписчика. То же самое касается оператора .do, который может пригодиться, но также действует как подписчик.

Я бы порекомендовал прочитать RxJs и взглянуть на пример с веб-сайта angulars, касающийся использования асинхронного канала.

Angular AsyncPipe — интересный пример нечистого пайпа. AsyncPipe принимает Promise или Observable в качестве входных данных и автоматически подписывается на ввод, в конечном итоге возвращая переданные значения.

оборудование.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';

export interface Equipment {
  name: string;
  id: string;
}

@Injectable()
export class EquipmentService {

  constructor(private http:Http){}

  public getDefaultEquipment(): Observable<Equipment[]> {
    return this.http
    .get('./app/SaveData/equipmentTest.json')
    .map((res:Response) => res.json());
  }
}

оборудование-list.component.ts

import { Component, OnInit } from "@angular/core";
import { EquipmentService, Equipment } from "./services/equipment.service";
import { Observable } from 'rxjs/Rx';

@Component({
  selector: 'equipment-list',
  templateUrl: './equipment-list.component.html',
  styleUrls: ['./equipment-list.component.css'],
  providers:[
     EquipmentService
  ]
})
export default class EquipmentComponent {

    constructor(private service: EquipmentService) {}

    public get equipment():Observable<Equipment[]> {
        return this.service.getDefaultEquipment();
    }
}

оборудование-list.component.html

<ul>
    <li *ngFor="item of (equipment | async)>
       <span>{{item.id}}</span>
       <span>{{item.name}}
    </li>
</ul>
person abdavid    schedule 22.11.2016
comment
Ответы лучше, когда есть какое-то объяснение с ними. Просто сказать «сделай это» не поможет нам понять, почему это работает именно так, и, следовательно, не поможет нам, если возникнет подобная ситуация. - person Jarod Moser; 23.11.2016
comment
Извиняюсь. был пропущен и опубликован до того, как объяснение было завершено. - person abdavid; 23.11.2016
comment
Ответ @abdavid правильный и хороший, хотя я бы не стал писать .map((res:Response) => res.json()); службе, потому что я хочу, чтобы мои компоненты реагировали на ответ: прочитали заголовки, код состояния и т. д. - person Aitch; 23.11.2016
comment
Если у вас есть компонент, который должен реагировать на определенные заголовки, то можно переместить .map((res:Response) => res.json()); туда, где это необходимо. Для этого примера этого должно быть достаточно, но спасибо за разъяснение. - person abdavid; 23.11.2016
comment
Это действительно познавательно и помогло прояснить несколько вопросов по реализации, которые у меня были. Спасибо за res:Response => res.abdavid() ;) - person nathan rogers; 23.11.2016
comment
не забудьте использовать *ngFor="let item of (equipment | async)" (вы забыли let перед item) - person ChumiestBucket; 28.09.2019