Pertanyaan Angular2 / RxJS - memperbarui variabel setelah mendapatkan data dari Http yang dapat diamati


Saya ingin mengaktifkan ikon loader saya (misalnya spinner) isLoaderEnabled ketika data mulai mengunduh dari API dan mematikannya ketika berhasil diterima. Apa cara yang tepat untuk mematikannya?

Ini kode saya berikut.

Komponen saya:

this.isLoaderEnabled = true;
this.meetingService.getList();

Layanan saya:

getList() {
  this._http.get('../fake-data/someFile.json')
    .map(response => response.json())
    .subscribe(
      data => {
        this.dataStore.meetingList = data;
        this.meetingListObserver.next(this.dataStore.meetingList);
      },
      err => console.log('>>>', 'Could not load meetings list. Error: ', err),
      () => console.log('>>>', 'Done with getting meetings list.')
    );
}

Terima kasih.


4
2018-04-11 16:20


asal


Jawaban:


Saya pikir masalah Anda paling sulit daripada yang terlihat pada pandangan pertama ;-) Bahkan, XHR tidak mendukung streaming sehingga ketika callback pertama terdaftar dalam subscribe metode ini disebut Anda sudah menerima semua data.

Yang mengatakan XHR mendukung onprogress acara (lihat plunkr ini: http://plnkr.co/edit/8MDO2GsCGiOJd2y2XbQk?p=preview). Ini memungkinkan untuk mendapatkan petunjuk tentang kemajuan pengunduhan. Ini tidak didukung di luar kotak oleh Angular2 tetapi Anda

@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
  constructor(private service:ProgressService) {}
  build(): any {
    let xhr = super.build();
    xhr.onprogress = (event) => {
      service.progressEventObservable.next(event);
    };
    return <any>(xhr);
  }
}

dan menimpa BrowserXhr penyedia dengan perpanjangan:

bootstrap(AppComponent, [
  HTTP_PROVIDERS,
  provide(BrowserXhr, { useClass: CustomBrowserXhr })
]);

Layanan kemajuan dapat diterapkan dengan cara ini:

export class ProgressService {
  progressEventObservable:Subject<any> = new Subject();
}

Layanan Anda dapat berlangganan layanan kemajuan untuk diberi tahu ketika unduhan benar-benar dimulai (yaitu pertama kali next metode dari progressEventObservable dipanggil untuk permintaan):

getList() {
  var subscription = this.progressService.subscribe(event => {
    if (!this.spinner) {
      this.spinner = true;
    }
  });
  this._http.get('../fake-data/someFile.json')
    .map(response => response.json())
    .do(val => this.spinner = true)
    .subscribe(
      data => {
        this.dataStore.meetingList = data;
        this.meetingListObserver.next(this.dataStore.meetingList);
      },
      err => (...),
      () => {
        this.spinner = false;
        subscription.unsubscribe();
      })
    );
}

Edit

Jika Anda ingin menggunakan spinner dalam komponen dan bukan layanan. Anda dapat menggunakan subjek / subjek yang dapat diamati, seperti yang dijelaskan di bawah ini:

spinner$: Subject<boolean> = new Subject();
spinner: boolean = false;

getList() {
  var subscription = this.progressService.subscribe(event => {
    if (!this.spinner) {
      this.spinner = true;
      this.spinner$.next(this.spinner); // <-------
    }
  });
  this._http.get('../fake-data/someFile.json')
    .map(response => response.json())
    .do(val => this.spinner = true)
    .subscribe(
      data => {
        this.dataStore.meetingList = data;
        this.meetingListObserver.next(this.dataStore.meetingList);
      },
      err => (...),
      () => {
        this.spinner = false;
        this.spinner$.next(this.spinner); // <-------
        subscription.unsubscribe();
      })
    );
}

Komponen dapat berlangganan spinner$ untuk diberi tahu tentang perubahan:

@Component({
  (...)
})
export class SomeCOmponent {
  constructor(private meetingService:MeetingService) {
    this.meetingService.spinner$.subscribe((spinner) {
      this.isLoaderEnabled = spinner;
    });
  }
}

8
2018-04-11 17:26



getList() {
  this._http.get('../fake-data/someFile.json')
    .map(response => response.json())
    .do(val => this.spinner = true)
    .subscribe(
      data => {
        this.dataStore.meetingList = data;
        this.meetingListObserver.next(this.dataStore.meetingList);
      },
      err => console.log('>>>', 'Could not load meetings list. Error: ', err),
      () => this.spinner = false)
    );
}

2
2018-04-11 16:22



Anda perlu membuat beberapa trik untuk membuatnya berfungsi dengan benar:

    //use Observable.from as lock trigger BEFORE request is sent
    var request:Observable<Response> = Observable.from([1], null).do(()=>
    {
        lock.lock();
    }).flatMap(()=>
    {
        //use finally to unlock in any case
        return this.http.post(url, body, options).finally(()=>
        {
            lock.unlock();
        });
    });
    //share sequence to avoid multiple calls when using several subscribers
    return request.share();

1
2018-04-11 16:43



Jika komponen Anda subscribe()s ke meetingListObserver, matikan saja dalam fungsi callback berlangganan.

Jika tidak, tambahkan Lainnya yang dapat diamati atau Subjek ke layanan dan minta komponen berlangganan. Ketika data kembali dari layanan, panggil next() pada yang Dapat Diobservasi atau Subjek. Untuk contoh menggunakan Subjek dalam layanan, lihat https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service


0
2018-04-11 21:43