2013-09-02 10 views
8

Ho una fabbrica che sta recuperando i dati da una fonte esterna. Non appena ottengo i dati, utilizzo una seconda fabbrica per filtrarla secondo determinati criteri.

La proprietà di fabbrica è assegnata all'ambito.

Ora, quando faccio questo nella mia fabbrica, che non aggiorna il campo di applicazione:

factory.foo = [{id:1,name:'foo'}]; // doesn't work 

Perciò anche il filterin in una seconda fabbrica non funziona

factory.foo = Filter.filter(); // doesn't work 

Anche se questo funziona :

factory.foo.push({id:1,name:'foo'}); // works 

qualcuno ha un'idea se questo è destinato e perché è in questo modo, e come risolverlo?

Full Sample plus plunkr

app.factory('Foo',function(Filter) { 
    var factory = { 
    foo:[], 
    getDataForFoo:function() { 
     factory.foo = Filter.filter(); // doesn't work 
     //factory.foo = [{id:1,name:'foo'},{id:1,name:'foo'}]; // doesn't work 
     //factory.foo.push({id:1,name:'foo'}); // works 
    } 
    }; 
    return factory; 
}); 

app.factory('Filter',function() { 
    var factory = { 
    filter:function() { 
     var arr = []; 
     arr.push({id:1,name:'foo'}); 
     return arr; 
    } 
    } 
    return factory; 
}); 

app.controller('MainCtrl', function($scope,Foo) { 
    $scope.test = 'running'; 
    $scope.foo = Foo.foo; 

    $scope.click = Foo.getDataForFoo; 
}); 

Plunkr

+3

È quello che dice Simon Belanger, si perde il riferimento. Lo spiego qui: http://angular-tips.com/blog/2013/08/consuming-services/ –

+0

Per una spiegazione completa dell'ereditarietà dell'ottica vedi questa risposta http://stackoverflow.com/questions/14049480/what- sono-the-nuances-of-scope-prototypal-prototypical-inheritance-in-angularjs – piatek

+0

@piatek non penso che sia correlato all'ereditarietà dell'ambito, in quanto ho un solo ambito qui. –

risposta

12

Il problema è che la vostra fabbrica sostituire il riferimento alla Factory.foo. Quando l'ambito è inizializzato, $scope.foo contiene un riferimento a un array (vuoto). Quando chiami Foo.getDataForFoo, modifica internamente il riferimento a Factory.foo ma il tuo ambito conserva ancora un riferimento alla matrice precedente. Questo è il motivo per cui l'uso di push funziona in quanto non cambia il riferimento dell'array, ma il contenuto dell'array.

Ci sono alcuni modi per risolvere questo problema. Senza andare in tutte le diverse opzioni, la più semplice è quella di avvolgere il tuo $scope.foo in una funzione, restituendo Factory.foo. In questo modo, Angular rileverà una modifica di riferimento in un ciclo di digest e aggiornerà la vista di conseguenza.

app.controller('MainCtrl', function($scope,Foo) { 
    $scope.test = 'running'; 
    $scope.foo = function() { return Foo.foo }; 

    $scope.click = Foo.getDataForFoo 
}); 

// And in the view (the relevant part) 

<ul ng-repeat="elem in foo()"> 
    <li>{{elem.id}} {{elem.name}}</li> 
</ul> 
<a href="" ng-click="click()">add</a> 
+0

grazie per questa spiegazione. è un buon approccio ... o c'è qualche pratica migliore/più pulita per questo? –

+1

È un buon approccio quando ci si aspetta cambiamenti di riferimento a qualcosa di esterno. Come hai scoperto, un'opzione è quella di modificare direttamente il contenuto dell'array (push, splice, ecc.) Oppure puoi spostare la logica della funzione in fabbrica (ad esempio, "Foo.foo' è una funzione che restituisce un array) ma tu dovrà ancora usare 'foo()' nel tuo modello. Un'altra opzione è recuperare nuovamente 'Foo.foo' dopo una chiamata a' getDataForFoo' come: '$ scope.click = function() {Foo.getDataForFoo(); $ scope.foo = Foo.foo; }; '.A questo punto, è davvero una questione di preferenza se ti piace usare le proprietà calcolate (funzione) o meno. –

+1

apprezzerei davvero il resto delle opzioni su come fare questo – user2422960

1

@ La risposta di Simon-Belanger è corretta e presenta una soluzione valida.

Un'altra opzione sarebbe semplicemente svuotare la matrice e inserirvi nuovi elementi (ad esempio per un evento di aggiornamento), anziché reimpostare il riferimento assegnandogli una nuova matrice. È possibile troncare un array assegnando alla lunghezza: myArray.length = 0 e quindi è possibile scorrere sulla nuova raccolta per popolare nuove voci tramite array.push()

+0

Grazie per me la tua idea ha funzionato meglio ... +1 :) – Genutek

Problemi correlati