2 votes

Exécuter les observables l'un après l'autre dans l'angle

J'ai un tableau d'objets avec les données suivantes :

 [  
   {  
      "name":"Uber",
      "points":20,   
      "nodeName":"C=GB,L=London,O=Uber",
      "port":10007,
      "nodeType":"merchant"
   },
   {  
      "name":"Starbucks",
      "points":20, 
      "nodeName":"C=US,L=New York,O=Starbucks",
      "port":10010,
      "nodeType":"merchant"
   },
   {  
      "name":"KFC",
      "points":20, 
      "nodeName":"C=US,L=New York,O=KFC",
      "port":10013,
      "nodeType":"merchant"
   }
]

Je souhaite parcourir ce tableau en boucle et afficher progrès déterminés La barre est animée et l'on doit également voir les points augmenter dans l'image ci-dessous. points et je veux les afficher l'un après l'autre, c'est-à-dire d'abord pour Uber, la barre de progression affichée se chargera jusqu'à 100% pour les points d'Uber, et ainsi de suite pour Starbucks, puis pour KFC.

enter image description here

J'ai essayé le code suivant, où res est mon tableau ci-dessus :

 res.forEach((v, i) => {
        Observable.timer(100).subscribe((i) => {
            let interval = Observable.interval(100).subscribe((i) => {
                this.percentageCom = (this.points / this.PointsAdded) * 100;
                if (this.percentageCom === 100) {
                    // this.isHidden = true;
                    interval.unsubscribe();
                }
            })
        });
    });
    let timer = Observable.interval(100).subscribe(() => {
        this.points++;
        if (this.points === 60) {
            timer.unsubscribe();
            // this.router.navigate(['/main/dashboard']);
        }
    });

et HTML :

<div class="vendor">{{merchantName|| 'Uber'}}</div>
<mat-progress-bar mode="determinate" value="{{percentageCom }}"></mat-progress-bar>

Mais le code ci-dessus n'affiche pas ma barre de progression l'une après l'autre car ces choses sont asynchrones, une sortie bizarre est affichée, à savoir l'affichage simultané de la barre de progression. Y a-t-il un moyen d'afficher le chargeur ci-dessus l'un après l'autre pour chaque élément du tableau ?

MISE À JOUR

Mon cas d'utilisation est le suivant :

  • Dans la réponse du service, j'obtiens un tableau d'objets comme indiqué ci-dessus.
  • Considérons le premier élément de ce tableau d'objets. Il a 20 points ; donc, à mon avis, les points devraient augmenter de 0 à 20 (comme un compteur).
  • Alors que l'incrémentation des points se produit jusqu'à 20, je veux afficher la barre de progression en pourcentage pour Uber dans ce cas, qui fonctionnera à 100%.
  • Une fois que les deux points ci-dessus ont été réalisés pour un objet, c'est-à-dire uber, il doit en être de même pour l'élément suivant dans le tableau de l'objet.

Voici les étapes que je souhaite mettre en œuvre. Mais comme interval y timer sont asynchrones, je ne suis pas en mesure de les exécuter l'un après l'autre en bouclant un objet.

Je me suis trompé de code dans le timer et l'intervalle... je n'ai pas réussi à m'en sortir !

3voto

Je ne vois pas exactement l'intérêt de simuler ce comportement de chargement, mais je pense que vous cherchez quelque chose comme ce bout de code. Je pense aussi, et l'exemple le montre, que vous pouvez supprimer la variable points mais je n'en suis pas sûr car je n'ai pas compris à 100% le contexte dans lequel vous vous trouvez.

const res =  [  
   {  
      "name":"Uber",
      "points":20,   
      "nodeName":"C=GB,L=London,O=Uber",
      "port":10007,
      "nodeType":"merchant"
   },
   {  
      "name":"Starbucks",
      "points":20, 
      "nodeName":"C=US,L=New York,O=Starbucks",
      "port":10010,
      "nodeType":"merchant"
   },
   {  
      "name":"KFC",
      "points":20, 
      "nodeName":"C=US,L=New York,O=KFC",
      "port":10013,
      "nodeType":"merchant"
   }
];

Rx.Observable.from(res)
.map( (value) => {
    return Rx.Observable.interval(100)
          .scan((acc, curr) => acc + 1)
          .take(value.points+1)
          .map(currentPoints => {
              const percentage = (currentPoints / value.points) * 100;
              return {arrayItem: value, percentage: percentage}
          })
})
 .concatAll()
 .subscribe((data) => {
    console.log(data.arrayItem.name + ': ' + data.percentage);
 });

<script src="https://npmcdn.com/@reactivex/rxjs@5.0.0-beta.8/dist/global/Rx.umd.js"></script>

Editer : J'ai édité la solution, elle est maintenant en série.

Explication :

  • Tout d'abord, nous convertissons notre tableau en un flux. Observable.from(res)'.
  • Pour chaque élément du tableau, maintenant dans le flux, nous le mappons dans un Observable.interval(100)
  • Nous prenons cet intervalle Observable et nous comptons les fois où il émet avec scan et nous le terminons en prenant seulement les éléments que le tableau item a.
  • Après cela, nous mettons en correspondance et renvoyons la valeur avec son pourcentage actuel.
  • L'opérateur concatAll() ne fait que concaténer la séquence d'observables dont nous disposons.
  • Enfin, la méthode "subscribe" n'affiche qu'un journal de console du résultat.

0voto

Witold Tkaczyk Points 233

Je ne suis pas sûr, mais je pense que vous faites un intervalle au mauvais endroit. Vous devriez le faire sur http get, ainsi vos abonnés pourront détecter les changements sur les observables avec des intervalles. Ce que vous cherchez s'appelle probablement demande de sondage et les hautes fréquences ici

article utile , problème connexe

exemple de fichier component.ts :

import { Component, OnInit } from '@angular/core';
import { Service } from './service';

@Component({
  selector: 'app-main',
  templateUrl: './main.component.html',
  styleUrls: ['./main.component.css']
})

export class MainComponent implements OnInit {

  constructor(private service: Service) { }

  ngOnInit() {

   this.service.getNewValue()
     .subscribe((res) => console.log(res));

  }

}

exemple de fichier service.ts :

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs'; // ! Dont forget to Import Observable !

@Injectable()

export class Service {

  constructor(private http: Http) { }

  getNewValue = () => {
    return Observable 
      .interval(1000)
      .flatMap((i) => this.http.get("http://yourhost.com/api"))
  }

}

Je ne l'ai pas testé, mais il devrait résoudre votre problème.

0voto

Robin Dijkhof Points 8254

Vous créez un nouveau minuteur pour chaque élément. Je ne pense pas que ce soit ce que vous voulez.

Je pense que vous voulez quelque chose comme ça :

res.forEach((v, i) => {
    //Add the point here because this is where your processing happens I guess?
    this.points++;
});

//Move it outside of your loop
$timer = Observable.timer(100).subscribe((i) => {// $timer as a local variable. 1000/60 might be better as it will refresh for every frame.
    this.percentageCom = (this.points / this.PointsAdded) * 100;
    if (this.percentageCom === 100) {
        // this.isHidden = true;
        this.$timer.unsubscribe();
    }
});

En outre, le processus sera probablement si rapide que vous ne le verrez pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X