2015-04-01 12 views
7

Im cercando per scorrere un array che costruisco da chiamate http multipli all'interno di un angular.forEach()iterare matrice quando forEach loop è tutto fatto

la funzione

$scope.ticket_stats = function(){ 
    //cleaning variables 
    $scope.data_set = []; 
    $scope.closed_tickets = []; 

    //fetching time stamps (epoch) 
    $scope.time_frame = time_period.days(7); 

       //calling data using time stamps 
       angular.forEach($scope.time_frame, function(item) { 
        //debug 
        console.log(item); 

        var promise = tickets.status("closed", item); 

        promise.success(function(data){ 
         console.log(data); 
         $scope.closed_tickets.push(data[0].datapoints[0][0]); // returns a numerical value 
        }); 

       }); 
       //SEE MESSAGE BELOW 
       $scope.data_set.push($scope.closed_tickets); 

} 

l'ultima riga $scope.data_set.push() funziona ma incremento se stesso nel tempo una volta chiama i dati di ritorno. Vorrei che questa riga fosse eseguita una volta terminato tutto all'interno di per ogni ciclo. Ho bisogno di scorrere l'array $scope.closed_tickets per riprodurre (aggiungere) i dati al suo interno e creare un secondo array.

qui sono i servizi utilizzati in questa funzione:

// CALL TICKETS STATS 
app.service('tickets', function($http){ 

    this.status = function(status, date){ 
     var one_snap = date - 100; 
     var url = "/url/render?format=json&target=sum(stats.tickets."+status+")&from="+one_snap+"&until="+date+""; 
     return $http.get(url); 
    };    
}); 

// TIME STAMPS MATHS 
app.service('time_period', function(){ 
    var currentDate = parseInt((new Date).getTime()/1000); 

    this.days = function(number){ 
     var pending = []; 
     for (var i = number; i > 0; i--) { 
      pending.push(currentDate - (87677*i)); 
     } 
     return pending; 
    }; 
}); 

ho la ricerca di informazioni e scoperto circa il servizio $q.all(), ma non sono riuscito a fare questo lavoro nel modo desiderato.

Qualsiasi consiglio sarebbe gradito! Grazie!

+0

avere uno sguardo a librerie di elaborazione asincrona come 'async.js' – floribon

+0

questo è simile ad usare il servizio di $ q. Questo è solo che non lo vedo funzionare. Una risposta più dettagliata sarebbe gradita. – SKYnine

+0

Non proprio, '$ q.all' sarà invocato quando tutte le promesse saranno risolte, ma saranno eseguite in parallelo. 'async' potrebbe aiutarti a sequenziarli, oppure puoi chiamare quello successivo una volta che il precedente ha terminato di usare' $ q.quando' – floribon

risposta

21

È possibile utilizzare $ q.all per attendere la fine di più eventi ansincronici (promesse).

$scope.ticket_stats = function() { 
    // list of all promises 
    var promises = []; 

    //cleaning variables 
    $scope.data_set = []; 
    $scope.closed_tickets = []; 

    //fetching time stamps (epoch) 
    $scope.time_frame = time_period.days(7); 

    //calling data using time stamps 
    angular.forEach($scope.time_frame, function(item) { 
     // create a $q deferred promise 
     var deferred = $q.defer(); 
     //debug 
     console.log(item); 

     tickets.status("closed", item).success(function(data) { 
      console.log(data); 
      $scope.closed_tickets.push(data[0].datapoints[0][0]); 

      // promise successfully resolved 
      deferred.resolve(data); 
     }); 

     // add to the list of promises 
     promises.push(deferred.promise); 
    }); 

    // execute all the promises and do something with the results 
    $q.all(promises).then(
     // success 
     // results: an array of data objects from each deferred.resolve(data) call 
     function(results) { 
      $scope.data_set.push($scope.closed_tickets); 
     }, 
     // error 
     function(response) { 
     } 
    ); 
} 

Innanzitutto, deferred rappresenta un pezzo di codice che avrà una quantità sconosciuta di tempo di esecuzione (asincrono). deferred.resolve(data) afferma semplicemente che il codice è finito. I dati possono essere qualsiasi cosa, un oggetto, una stringa, qualunque cosa, ma di solito sono i risultati del tuo codice asincrono. Allo stesso modo è possibile rifiutare una promessa con deferred.reject(data) (forse un errore è stato generato dal sever). Ancora una volta, i dati possono essere qualsiasi cosa ma qui dovrebbe probabilmente essere la risposta all'errore.

deferred.promise restituisce appena un oggetto promessa. L'oggetto promessa consente di impostare i callback come .then(successFunction, errorFunction) in modo da sapere che un pezzo di codice ha completato l'esecuzione prima di passare a successFunction (o errorFunction in caso di errore). Nel nostro caso $q ha il metodo .all che aspetta una serie di promesse per finire poi ti dà i risultati di tutte le promesse come una matrice.

Non dimenticare di iniettare il servizio $q.

+0

ok quindi per sicurezza, diciamo che ho due chiamate da effettuare al posto di una (es. : ticket.status ('closed'). Devo solo duplicare questo bit e utilizzare lo stesso deferred.resolve (dati) al suo interno? (seguendo il tuo esempio. – SKYnine

+0

Dipende dal fatto che la chiamata 2 avvenga dopo la chiamata 1 o allo stesso tempo: se si verifica la chiamata 1 e quindi si verifica la chiamata 2 (la chiamata 2 è nidificata all'interno della chiamata 1) si sposta semplicemente 'deferred.resolve' all'interno di' call2.success'. Altrimenti si avrebbe '$ q. tutto ([call1, call2]) 'all'interno del ciclo forEach. Dove call1 e call2 hanno ciascuno un oggetto posticipato e risolvono la chiamata. – csbarnes

1

Cerca di creare solo una serie di promesse, senza risolverle. Quindi aggregali con $ q.all(). Dopo la promessa aggregata, risolvi di nuovo l'iterazione attraverso la serie di quelle promesse. Ora sei sicuro che siano tutti risolti.

var promises = []; 
angular.forEach($scope.time_frame, function(item) { 
    promises.push(tickets.status("closed", item)); 
}); 

var aggregatedPromise = $q.all(promises); 

aggregatedPromise.success(function(){ 
    angular.forEach(promises, function(promise) { 
     promise.success(function(data){ 
      $scope.closed_tickets.push(data[0].datapoints[0][0]); // returns a numerical value 
     }); 
    }); 
}); 

Forse questo non è il modo più efficiente per farlo, ma penso che dovrebbe risolvere il tuo problema.

1

Anche se hai menzionato $ q.tutto non ha funzionato per te, perché non vedo perché non dovrebbe, ecco come farei questo.

In pratica si desidera mappare una serie di elementi (indicatori di data e ora) ad alcune altre cose (promesse in questo caso poiché abbiamo chiamate asincrone) e fare qualche azione sull'array risultante.

var promises = $scope.time_frame.map(function (item) { 
    return tickets.status("closed", item); 
}); 

Ora usiamo $q.all aspettare che tutte le promesse di risolvere:

$q.all(promises).then(function (tickets) { 
    $scope.data_set.push(tickets); 
}); 
Problemi correlati