Tengo una matriz de objetos con los siguientes datos:

 [  
   {  
      "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"
   }
]

Quiero recorrer esta matriz y mostrar determinar el progreso barra con animación y también debería ver que los puntos aumentan en la vista que se muestra en la imagen a continuación. para el atributo points y desea mostrarlo uno tras otro. es decir, primero para la barra de progreso de Uber mostrada, que se cargará hasta el 100% para los puntos de uber. y así sucesivamente para Starbucks y luego para KFC.

enter image description here

He intentado debajo del código, donde res es mi matriz anterior:

 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']);
        }
    });

Y HTML:

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

Pero el código anterior no muestra mi barra de progreso una tras otra, ya que esas cosas son asíncronas, se muestran algunos resultados extraños, es decir, muestran simultáneamente la barra de progreso. ¿Hay alguna forma de mostrar el cargador anterior uno tras otro para cada elemento de la matriz?

ACTUALIZADO

Mi caso de uso es el siguiente:

  • De la respuesta del servicio obtengo una matriz de objetos como se menciona anteriormente
  • Consideremos el primer elemento de ese conjunto de objetos. Tiene puntos 20; en mi vista, los puntos deberían aumentar de 0 a 20 (al igual que el contador)
  • Entonces, aunque este incremento de puntos ocurre hasta 20, quiero mostrar la barra de progreso porcentual para Uber en este caso, que se ejecutará al 100%.
  • Una vez por encima de 2 puntos completos para un objeto, es decir, debe suceder lo mismo para el siguiente elemento en la matriz del objeto.

Arriba están los pasos que quiero implementar. Pero como interval y timer son asíncronos, no puedo ejecutarlo uno tras otro haciendo un bucle de objeto abpve.

He estropeado el código allí en temporizador e intervalo ... ¡de alguna manera no pude superarlo!

2
user1608841 30 oct. 2017 a las 14:39

3 respuestas

La mejor respuesta

No encuentro exactamente el propósito de burlarse de ese comportamiento de carga, pero creo que está buscando algo como este código cortado. Creo que también, y el ejemplo muestra, que puede eliminar la variable de puntos ... pero no estoy seguro porque no entendí al 100% el contexto en el que se encuentra.

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>

Editar : edité la solución, ahora está en serie.

Explicación :

  • Primero convertimos nuestra matriz en una secuencia. 'Observable.from (res)'.
  • Para cada elemento de la matriz, ahora en la secuencia, lo asignamos a un Observable.interval (100)
  • Tomamos ese intervalo Observable y contamos las veces que se emite con el escaneo y lo terminamos tomando solo como elementos como punto que tiene el elemento de matriz.
  • Después de eso mapeamos un retorno del valor con su porcentaje actual.
  • El operador concatAll () simplemente concatena la secuencia observable que tenemos.
  • Finalmente, el método de suscripción solo muestra un registro de consola del resultado
3
Llorenç Pujol Ferriol 31 oct. 2017 a las 08:22

Estás creando un nuevo temporizador para cada elemento. No creo que eso sea lo que quieres.

Creo que quieres algo como esto:

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();
    }
});

Además, esto probablemente se procesará tan rápido que no lo verá.

0
Robin Dijkhof 30 oct. 2017 a las 13:12

No estoy seguro, pero creo que estás haciendo un intervalo en el lugar equivocado. Debe hacer esto en http get, luego sus suscriptores detectarán los cambios en los observables con intervalos. Lo que está buscando probablemente se llama solicitud de sondeo y aquí se encuentran frecuencias altas

artículo útil, problema relacionado

Archivo de ejemplo 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));

  }

}

Archivo de ejemplo 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"))
  }

}

No lo probé pero debería solucionar tu problema

0
Witold Tkaczyk 30 oct. 2017 a las 12:40