2014-10-24 2 views
5

Nella mia direttiva personalizzata, sto aggiungendo elementi al DOM in base al numero di oggetti nella mia matrice di datasource. Devo guardare una proprietà specifica in ogni oggetto. Mentre aggiungo questi elementi al DOM, voglio impostare un $ watch sulla proprietà checked di ciascun oggetto nell'array toppings, ma non funziona, e non so perché. Ho impostato un breakpoint all'interno della funzione che deve essere invocato quando la proprietà passa da true a false o false a true, ma quella funzione non viene mai richiamata. La ragione è ovvia? Sto solo imparando Angular, quindi potrei facilmente fare un errore stupido.AngularJS: guardare una particolare proprietà in una matrice di oggetti per le modifiche nel valore della proprietà

$scope.bits = 66; (i.e. onions and olives) 


$scope.toppings = [ 
    { topping: 1, bits: 2, name: 'onions' }, 
    { topping: 2, bits: 4, name: 'mushrooms' }, 
    { topping: 3, bits: 8, name: 'peppers' }, 
    { topping: 4, bits: 16, name: 'anchovies' }, 
    { topping: 5, bits: 32, name: 'artichokes' }, 
    { topping: 6, bits: 64, name: 'olives' }, 
    { topping: 7, bits: 128, name: 'sausage' }, 
    { topping: 8, bits: 256, name: 'pepperoni' } 
    ] 

Ogni oggetto nel modello ottiene un nuovo checked proprietà che sarà vero o falso.

NOTA: l'array di oggetti contiene al massimo una dozzina di elementi. Le prestazioni non sono una preoccupazione.

link: function link(scope, iElement, iAttrs, controller, transcludeFn) { 


    <snip> 

// At this point scope.model refers to $scope.toppings. Confirmed. 

    angular.forEach(scope.model, function (value, key) { 

    // bitwise: set checked to true|false based on scope.bits and topping.bits 

    scope.model[key].checked = ((value.bits & scope.bits) > 0); 


    scope.$watch(scope.model[key].checked, function() { 
     var totlBits = 0; 
     for (var i = 0; i < scope.model.length; i++) { 
      if (scope.model[i].checked) totlBits += scope.model[i].bits; 
     } 
      scope.bits = totlBits; 
     }); 

    }); 

    <snip> 

risposta

1

Il parametro watchExpression in $ scope. $ Watch deve essere una stringa o una funzione. Non ho mai fatto molte ricerche su questo (cerco di evitare orologi espliciti dove possibile), ma penso che funzioni anche quando guardi le proprietà del "semplice" scope come riferimenti a oggetti, ma non così bene con riferimenti più complessi.

Penso che se si fornisce il riferimento come una stringa, ad es. 'model [' + key + '] .checked' allora potresti avere qualche successo (dico solo perché ho già fatto qualcosa di simile con $ watchCollection in precedenza).

In alternativa, è possibile fornire una funzione, ad es.

$scope.$watch(function() { return scope.model[key].checked; }, function() { ... });

Spero che questo aiuti!

+0

L'approccio della funzione ha funzionato. Grazie! – Tim

+0

Lo svantaggio di questo approccio è che si sta creando un osservatore per chiave sull'oggetto. $ WatchCollection è più performante. –

+1

@William Lepinski: Puoi spiegare perché una watchCollection sull'array, che deve guardare ogni proprietà su ogni oggetto, si comporta meglio di un orologio solo sulla proprietà che ho bisogno di vedere? Non sono in disaccordo, vorrei solo sapere come si fa. Come viene implementata una vigilanza approfondita? – Tim

0

Utilizzare invece $watchCollection.

Dalla documentazione:

$ watchCollection (obj, ascoltatore); Shallow controlla le proprietà di un oggetto e si attiva ogni volta che una delle proprietà cambia (per gli array, questo implica la visione degli elementi dell'array, mentre per le mappe degli oggetti ciò implica la visione delle proprietà). Se viene rilevata una modifica, viene attivato il callback del listener.

La raccolta degli oggetti viene osservata tramite l'operazione standard $ watch ed è esaminata su ogni chiamata a $ digest() per verificare se alcuni articoli sono stati aggiunti, rimossi o spostati. L'ascoltatore viene chiamato ogni volta che qualcosa all'interno dell'oggetto è stato modificato. Gli esempi includono l'aggiunta, la rimozione e lo spostamento di elementi appartenenti a un oggetto o array.

+1

ma guarda tutte le proprietà di una collezione. non solo una singola proprietà. In questo caso OP vuole vedere solo la proprietà 'checked'. – harishr

+0

Bene, puoi cogliere l'array afferrando solo la proprietà selezionata. Assegna questo array appena creato all'ambito e usa $ watchCollection per controllare la matrice delle proprietà verificate. –

2

Array di oggetti:

$scope.toppings = [ 
    { topping: 1, bits: 2, name: 'onions' }, 
    { topping: 2, bits: 4, name: 'mushrooms' }, 
    { topping: 3, bits: 8, name: 'peppers', checked:undefined /*may be*/ } 
]; 

Guarda utilizzando AngularJs $ WatchCollection:

Invece di monitoraggio objects matrice sopra, che può cambiare in qualsiasi proprietà nell'oggetto, creeremo un matrice di proprietà degli elementi per i quali stiamo guardando la raccolta (.checked).

Abbiamo filter elementi della matrice per monitorare solo quegli elementi che sono definiti e .checkedmap che a un array per angolare watchCollection.

Quando si verifica un cambiamento, confronterò il vecchio e il nuovo array di (.checked) per ottenere l'elemento modificato corretto utilizzando il metodo lodash difference.

$scope.$watchCollection(
       //Watch Function 
       ()=>($scope.toppings.filter(tp=>tp.checked!=undefined).map(tp=>tp.checked)), 

       //Listner 
       (nv,ov)=>{ 
       if(nv==ov||nv=="undefined")return; 

       //Use lodash library to get the changed obj 
       let changedTop= _.difference(nv,ov)[0]; 

       //Here you go.. 
       console.log("changed Topping",changedTop); 
      }) 
+1

Questa è una delle risposte migliori nella mia opinione, e funziona molto meglio per gli array, tuttavia nell'interesse dell'autore della domanda e di chiunque altro cerchi aiuto su questo, dovresti aggiungere più dettagli alla tua risposta per spiegare che stai usando il tipo di script e spiegare il tuo ragionamento per filtrare e mappare la matrice. Altrimenti un'ottima soluzione. – Squall

+0

Questo non è TypeScript ma Javascript ES6 :-). Modificato per il motivo dell'applicazione del filtro. – ahmadalibaloch

+0

Penso che questo funzioni solo nel caso molto specifico (quello che sembra essere l'OP, come hanno menzionato in un'osservazione) che la proprietà osservata non ha più di due stati. –

1

si utilizza MAP per raccogliere tutti i valori delle proprietà è necessario + convertirli in una piccola rappresentazione di stringa (in questo caso 1 e 0) e poi unirli insieme in una stringa che può essere osservato.

Un esempio dattiloscritto:

 $scope.$watch(
      () => this.someArray.map(x => x.selected ? "1" : "0").join(""), 
      (newValue, oldValue, scope) => this.onSelectionChanged(this.getSelectedItems())); 
+1

Sospetto che questo sia un po 'più performante di prima facendo un 'filter' e poi un' map' come nell'altra risposta di @ahmadalibaloch –