2017-05-26 1 views
0

Say I ont une composante angulaire 2 comme ceci:RxJS abonnements multiples à boutons alloués dynamiquement

import { Component, AfterViewInit, ViewChildren, QueryList, ElementRef } from '@angular/core'; 
import { Observable } from 'rxjs/Rx'; 
import {ApiService} from './my.service' 
@Component({ 
    selector: 'my-component', 
    template: ` 
    <div class='button0' [ngClass]="{selected: selection === 0}" #button>Hello World</div> 
    <div class='button1' [ngClass]="{selected: selection === 1}" #button>Hello World</div> 
    `, 
    styles: [` 
    .selected { 
    color: red; 
    } 
    `], 
    providers: [ApiService] 
}) 
export class MyComponent implements AfterViewInit { 
    selection = 0; 
    @ViewChildren('button') buttons: QueryList<ElementRef>; 
    buttonObservables:any[] = null; 

    constructor(private api: ApiService) {} 

    updateServer(index) { 
    api.requestsExample(index) 
     .then((result) => { 
     //update other divs and stuff 
     } 
    } 


    updateColor(index) { 
    this.selection = index; 
    } 

    ngAfterViewInit() { 
    this.buttonObservables = this.buttons.map((button) => Observable 
     .fromEvent<MouseEvent>(button.nativeElement, 'click')); 

    this.buttonObservables.map((observable) => { 
     observable.throttleTime(2000).subscribe((event:MouseEvent) => { 
      const element:Element = event.target as Element; 
     this.updateServer(element.classList[1].match(/\d+/g)); 
     }) 
    }); 

    this.buttonObservables.map((observable) => { 
     observable.subscribe((event:MouseEvent) => { 
     const element:Element = event.target as Element; 
     this.updateColor(element.classList[1].match(/\d+/g)); 
     }) 
    }); 
    } 
} 

où ApiService.requestsExample

est une fonction annotée asynchrone qui en fait la demande et renvoie une réponse.

Le code à peu près œuvres (par exemple, les demandes sont étranglées, bouton empâtage ne donne pas trop de demandes, les couleurs changent encore)

Je me bats pour comprendre pour gérer la EdgeCase suivante: 1) Je Comme pour garantir que le résultat qui a été tiré en dernier est celui dont la réponse est acceptée (en supposant que la réponse revienne), et ensuite travailler dans l'ordre chronologique. Je ne suis pas sûr de savoir comment y parvenir en raison du fait que les demandes sont asynchrones? 2) (corollaire) Afin d'éviter les scintillements lors de la mise à jour, je souhaite également annuler tous les résultats renvoyés par le serveur lorsqu'un résultat ultérieur revient (en fonction de l'ordre des problèmes plutôt que de l'ordre de réponse). 3) Une fois la dernière requête live en cours renvoyée, je voudrais abandonner toutes les observables en cours, car je ne m'en soucie plus. Donc, en gros, si un utilisateur écrase les deux boutons pendant 20 secondes, je m'attendrais à faire 10 requêtes, mais à l'exception de changer les couleurs des boutons, mettre à jour l'interface utilisateur une fois, et à la bonne valeur.

De plus je voudrais juste aimer des commentaires s'il y a une meilleure façon de parvenir à ce résultat avec Observables (ou même si observables sont l'outil pour ce travail!)

Répondre

1

Expliquons le RxJS 5 exemple ci-dessous:

  • Vous voulez faire updateServer une partie du calcul réactif, donc vous le faites retourner un observable.
  • Puisque vous traitez tous les clics de la même manière, il est logique de mergeAll tous les clics de différents boutons.
  • Étant donné que vous n'utilisez que l'index du bouton pour le calcul, il est logique de cliquer simplement sur map.
  • Vous pouvez faire immédiatement le updateColor comme effet secondaire avec do.
  • debounceTime(1000) émet un clic uniquement après qu'une seconde soit passée sans autres clics. Je pense que c'est mieux que Throttle que vous ne voulez pas faire des appels réseau inutiles si l'utilisateur fait plusieurs clics rapides. Seul le dernier.
  • Puisque vous voulez annuler le updateServer précédent lorsqu'un nouveau clic vient, il est logique d'utiliser switchMap. Il mappe un clic sur un nouveau updateServer observable puis l'abandonne et passe à un nouveau si un nouveau clic arrive.
  • Puisque vous voulez ignorer tous les autres clics après le premier updateServer, ou c'est ainsi que je comprends 3), take(1) prendra un résultat et complétera toute la chaîne.
updateServer(index) { 
    return Observable.fromPromise(api.requestsExample(index)) 
} 

this 
    .buttonObservables 
    .mergeAll() 
    .map(ev => ev.target.classList[1].match(/\d+/g)) 
    .do(idx => this.updateColor(idx)) 
    .debounceTime(1000) 
    .switchMap(idx => this.updateServer(idx)) 
    .take(1) 
    .subscribe(result => { 
    // update other divs 
    }) 
+0

C'est incroyable! Je vous remercie :) –