2016-02-05 10 views
9

Ho un credito direttiva treeview a http://codepen.io/bachly/pen/KwWrzG per essere il mio blocco di partenza. che sto cercando di aggiornare quando aggiungo oggetti alla collezione. Posso aggiornare l'oggetto e inserire i nuovi oggetti ma la direttiva treeview non viene mai chiamata dopo che l'elemento $scoped è stato aggiornato. In definitiva i dati utilizzati verranno da un servizio a questo punto sto solo testando con dati falsi.Aggiornare una direttiva treeview angolare quando un nuovo oggetto viene aggiunto alla raccolta

La collezione originale assomiglia a questo

$scope.myList = { 
      children: [ 
       { 
        name: "Event", 
        children: [ 
        { 
         name: "Event Date", 
         parent:"Event", 
         children: [ 
          { 
           name: "2008", 
           filterType: '_eventStartDate', 
           parent: 'Event' 
          }, 
          { 
           name: "2009", 
           filterType: '_eventStartDate', 
           parent: 'Event' 
          } 
         ] 
        }, 
        { 
         name: "Event Attendee", 
         parent: "Event", 
         children: [ 
          { 
           name: "Person 1", 
           filterType: '_eventAttenddeeName', 
           parent: 'Event Attendee' 
          }, 
          { 
           name: "Person 2", 
           filterType: '_eventAttenddeeName', 
           parent: 'Event Attendee' 
          } 
         ] 
        } 
        ] 
       }] 
    }; 


    var TheOtherCollection = { 
     children: [ 
     { 
      name: "A New Event", 
      children: [ 
       { 
        name: "The Other Date", 
        parent: " A New Event", 
        children: [ 
        { 
         name: "2010", 
         FilterType: '_eventStartDate', 
         Parent: '_event' 
        }, 
        { 
         name: "2011", 
         FilterType: '_eventStartDate', 
         Parent: '_event' 
        } 
        ] 
       } 
      ] 
     }] 
    }; 

Questo genera una vista ad albero con le caselle di controllo utilizzando la seguente direttiva e html

app.directive('tree', function() { 
    return { 
     restrict: 'E', 
     replace: true, 
     scope: { 
      t: '=src', 
      filter: '&' 
     }, 
     controller: 'treeController', 
     template: '<ul><branch ng-repeat="c in t.children track by $index" src="c" filter="doSomething(object, isSelected)"></branch></ul>' 
    }; 
}); 

app.directive('branch', function($compile) { 

    return { 
     restrict: 'E', 
     replace: true, 
     scope: { 
      b: '=src', 
      filter: '&', 
      checked: '=ngModel' 
     }, 

      template: '<li><input type="checkbox" ng-click="innerCall()" ng-model="b.$$hashKey" ng-change="stateChanged(b.$$hashKey)" ng-hide="visible" /><a>{{ b.name }}</a></li>', 
      link: function (scope, element, attrs) { 

       var clicked = ''; 
       var hasChildren = angular.isArray(scope.b.children); 
       scope.visible = hasChildren; 
       if (hasChildren) { 
        element.append('<tree src="b"></tree>'); 
        $compile(element.contents())(scope); 
       } 
       element.on('click', function(event) { 
        event.stopPropagation(); 
        if (hasChildren) { 
         element.toggleClass('collapsed'); 
        } 
       }); 
       scope.stateChanged = function(b) { 
        clicked = b; 
       }; 

       scope.innerCall = function() { 
        scope.filter({ object: scope.b, isSelected: clicked }); 
       }; 
      } 
     }; 
    }); 

E poi l'html

<div ng-controller="treeController"> 
     <tree src="myList" iobj="object" filter="doSomething(object, isSelected)"></tree> 

     <a ng-click="clicked()"> link</a> 
    </div> 

Quando un viene selezionata la casella di controllo la nuova raccolta viene aggiunta a quella esistente utilizzando loda shjs

ng-click evento

$scope.doSomething = function (object, isSelected) { 
    if (isSelected) { 
     var item = object; 
     console.log(item); 
     nestAssociation(object, $scope.myList, TheOtherCollection); 
    } 
} 

che crea il nuovo array e lo aggiunge all'interno dell'array bambini

function nestAssociation(node, oldCollection, newAggregates) { 
    // var item = fn(oldCollection, node.parent); 
    var updatedArray = _.concat(oldCollection.children, newAggregates); 
    console.log(updatedArray); 
    if (updatedArray != null) 
     updateMyList(updatedArray); 
} 

posso vedere nell'output ho un nuovo oggetto ma non posso' t ottenere la vista ad albero per aggiornare. Ho provato all'interno della direttiva di aggiungere un $ compile (elemento) all'evento click nella direttiva, ma poiché l'array non è stato creato, non cambia nulla.

Devo aggiungere un $ watch a questa direttiva e, in caso affermativo, dove o c'è un altro modo in cui posso ottenere la direttiva per ri-renderizzare e visualizzare la nuova raccolta nidificata?

Aggiornamento

Base su alcuni dei commenti e domande qui è un po 'più in dettaglio intorno alla questione. Il problema che sto vedendo non è nella direttiva per quanto riguarda lo spostamento dei dati attorno al problema è che non riesco a ri-renderizzare il treeview una volta aggiunto un array al modello esistente. Il seguente collegamento is a working plunker che mostra il progetto mentre attualmente funziona. corso strumenti di Chrome dev posso vedere in uscita il modello viene aggiornato dopo una casella di controllo è selezionata enter image description here

Mentre vedo l'oggetto viene aggiornato, la direttiva non aggiorna per mostrare il nuovo array aggiunto all'oggetto. Questa è la parte che ho bisogno di aiuto per capire.

grazie in anticipo

+1

Sarebbe bello se poteste creare un plunkr o una codepen in cui potessimo vedere il problema reale e lavorare nel vostro codice (come ho capito, la codepen collegata era solo il vostro punto di partenza). –

+0

Puoi pubblicare il codice della tua funzione 'updateMyList' che è chiamata da' nestAssociation() '. Immagino che questo sia dove effettivamente salvi l'array aggiornato in '$ scope.myList' –

+1

Ho aggiornato la mia domanda con un link plunker – rlcrews

risposta

4

si passa la funzione alle direttive interne (che è la migliore pratica), ma si ha accesso a scope.filter. Non doSomethingFunction. Questo è undefined lì.

filter="doSomething(object, isSelected)"
=>
filter="filter(object, isSelected)"

app.directive('tree', function() { 
    return { 
     restrict: 'E', 
     replace: true, 
     scope: { 
      t: '=src', 
      filter: '&' 
     }, 
     controller: 'treeController', 
     template: '<ul> 
        <branch ng-repeat="c in t.children track by $index"  
        src="c" filter="filter(object, isSelected)"> 
        </branch> 
        </ul>' 
    }; 
}); 

successivo:

non si può mai accedere $$ variabili in angularJS, perché sono private. Forse dovresti crearne uno dal tuo DB ..., ma il $$hashkey sembra una soluzione semplice.

l'attributo checked potrebbe generare un errore, perché ngModel non esiste nel modello di direttiva dell'albero. (inserire almeno un ? prima)

Una casella di controllo non può avere come modello un hashkey $$.
Ng-change e ng-click verranno sempre chiamati allo stesso tempo, utilizzare il più semplice.

app.directive('branch', function($compile) { 

    return { 
     restrict: 'E', 
     replace: true, 
     scope: { 
      b: '=src', 
      filter: '&' 
     }, 

      template: '<li><input type="checkbox" ng-click="innerCall(b.$$hashKey)" ng-model="isChecked" ng-hide="visible" /><a>{{ b.name }}</a></li>', 
      link: function (scope, element, attrs) { 

       scope.isChecked = false; 
       var hasChildren = angular.isArray(scope.b.children); 
       scope.visible = hasChildren; 
       if (hasChildren) { 
        element.append('<tree src="b"></tree>'); 
        $compile(element.contents())(scope); 
       } 
       element.on('click', function(event) { 
        event.stopPropagation(); 
        if (hasChildren) { 
         element.toggleClass('collapsed'); 
        } 
       }); 

       scope.innerCall = function(hash) { 
        if(scope.isChecked){ 
         scope.filter({ object: scope.b, isSelected: hash }); 
        } 

       }; 
      } 
     }; 
    }); 

UPDATE

avete gli stessi treeController nella direttiva tree e nella vostra index.html vista. Questo è ciò che fa sì che la vista non si aggiorni!

Ho eliminato quello nella direttiva, altrimenti avrò un controller per ogni bambino.
Hai visto il buon messaggio console.log nel tuo controller, ma era in un controller per UNA direttiva.
Non si stava accedendo al controller dello index.html.

Poi ho fissato la comunicazione filter funzione tra bambino:

Hai dimenticato di comunicare la funzione di filtro, quando si aggiunge nuove s tree':

element.append('<tree src="b" filter="filter({ object: object, isSelected: isSelected })"></tree>');

Inoltre, nel modello direttiva madre, è necessario anche l'hash per inviare parametri alla funzione:
filter="filter({ object: object, isSelected: isSelected })"

Ho modificato il tuo Plunker HERE senza modificare il codice con i commenti sopra che ho fatto.
(Non sono sicuro che quello che scrivi non è quello che vuoi e perché non hai commentato io preferisco non cambiarlo in modo da rendere ancora più veloce il tuo codice)
Ma la vista si sta aggiornando ora!
Penso che un po 'di debug con quello che vuoi e i commenti sopra dovrebbero essere abbastanza.

EDIT 2
ti sei dimenticato di restituire un oggetto con la proprietà chrilden. Hai restituito un array, che ha causato il problema.

function updateMyList(data) { 
     var transformed = { children : data }; 
     $scope.myList = transformed; 
    } 

Qui è un lavoro PLUNKER.

0

Prova $ ambito. $ Applicare() dopo l'aggiunta di

+0

Provato all'inizio di $ scope. $ Apply() o $ scope. $ Apply (function() {...}) non funzionerà in quanto la funzione è attualmente in un ciclo $ apply(). Quindi non può richiamarne uno nuovo – rlcrews

+1

@ricrews È possibile evitare il problema del ciclo $ apply avvolgendo la chiamata in $ scope. $ Applicare in una chiamata $ timeout – twsaef

Problemi correlati