2013-03-20 19 views
5

Sto provando a fare un po 'di rilegatura complessa con knockout (almeno per un principiante come me).knockout.js binding ricorsivo

Considerate i seguenti dati:

var originalData = { 
id: 1, 
name: "Main", 
children: [ { id: 2, name: "bob", children: []}, { id: 3, name: "ted", children: [{id: 5, name:"albert"}, {id: 9, name: "fred"}]} ], 
selectedChild: { id: 2, name: "bob" } 
}; 

<table> 
<tr> 
    <td data-bind="text: name"></td> 
</tr> 
<tr data-bind="if: children().length > 0"> 
    <td> 
     <select data-bind="options: children, 
      optionsText: function(item){ 
       return item.name; 
        }, 
      optionsCaption: 'Choose...'"></select>  
    </td> 
</tr> 

Ok, questa era la parte facile.

La parte difficile, è che ogni volta che un elemento viene selezionato nell'elenco, se questo elemento ha figli, dovrebbe apparire una nuova casella di selezione sotto. La sua origine dati sarebbe i figli dell'elemento selezionato nella prima casella di selezione. Certo, potrebbe continuare con qualsiasi livello di profondità.

Come dovrei risolvere questo problema con knockout?

Ho messo insieme un campione di ciò che ho finora su jsfiddle: http://jsfiddle.net/graphicsxp/qXZjM/

+0

un'idea che mi viene in mente, è quello di utilizzare un modello con la stessa casella di selezione all'interno e aggiungere tale modello all'elemento tabella quando si seleziona una voce con i bambini. Non è ancora chiaro come lo farò, ma pensi che sia sulla strada giusta? – Sam

risposta

9

È possibile utilizzare i modelli ricorsivi in ​​knockout mettendo il modello in un tag script. Modelli in un tag script possono fare riferimento se stessi, in questo modo:

<div data-bind="template: 'personTemplate'"></div> 

<script type="text/ko" id="personTemplate"> 
    <span data-bind="text: name"></span> 
    <select data-bind="options: children, optionsText: 'name', optionsCaption: 'Choose', value: selectedChild"></select> 
    <!-- ko if: selectedChild --> 
    <div data-bind="template: { name: 'personTemplate', data: selectedChild }"></div> 
    <!-- /ko --> 
</script> 

Ecco the fiddle


Aggiornamento:

È possibile utilizzare un computed per fare facilmente questo, e rimuovere la logica dal punto di vista (che ritengo sia meglio in questo caso), e quindi legare il if ad esso.

self.showChildren = ko.computed(function() { 
    return self.selectedChild() 
     && self.selectedChild().children().length > 0; 
}); 

Se si desidera inserire sia nel blocco if, è possibile, basta per includere le parentesi. La ragione di ciò è che le osservabili sono funzioni; knockout ti consente di escluderli se stai usando il riferimento singolo, ma sono obbligati a "approfondire" le loro proprietà.

if: selectedChild() && selectedChild().children().length > 0 

Ecco la updated fiddle

+0

Grazie mille, sembra fantastico! È praticamente ciò di cui ho bisogno. Solo una cosa però, non riesco a farlo funzionare usando il plugin di mappatura mentre si è utilizzata una funzione Person codificata. Potresti indicarmi cosa sto facendo di sbagliato? jsfiddle qui: http://jsfiddle.net/graphicsxp/qXZjM/ – Sam

+0

effettivamente ignora il mio commento, funziona ora. Ho solo bisogno di impostare le proprietà selectedChild su ko.observable(). Molte grazie ! – Sam

+0

un'ultima domanda: come modificheresti l'if in modo che il modello mostri solo se c'è almeno un figlio per il bambino selezionato? Ho provato ko se: selectedChild && selectedChild.children.length> 0 ma non funziona ... Qualche idea? – Sam

Problemi correlati