2013-03-20 14 views
5

Próbuję wykonać pewne skomplikowane powiązanie z nokautem (przynajmniej dla początkującego takiego jak ja).knockout.js wiązanie rekursywne

Rozważmy następujące dane:

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, to było łatwe.

Najtrudniejszą częścią jest to, że po wybraniu elementu na liście, jeśli ten element ma elementy podrzędne, powinno pojawić się pod nim nowe pole wyboru. Jego źródłem danych będą dzieci wybranego elementu w pierwszym polu wyboru. Oczywiście można go było kontynuować na dowolnym poziomie głębokości.

Jak powinienem rozwiązać ten problem przez nokaut?

I już ułożyła próbkę tego, co mam do tej pory na jsfiddle: http://jsfiddle.net/graphicsxp/qXZjM/

+0

jeden pomysł, który przychodzi mi na myśl, jest użycie szablonu z tym samym polu wyboru wewnątrz tego szablonu i dołączyć do elementu tablicy, gdy wybrany element z dziećmi. Nie jest jeszcze jasne, jak mam to zrobić, ale czy myślisz, że jestem na dobrej drodze? – Sam

Odpowiedz

9

Można użyć cyklicznych szablonów nokautem umieszczając szablon w script tagu. Szablony w script tagu może odwoływać się w następujący sposób:

<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> 

Oto the fiddle


Aktualizacja:

Można użyć computed łatwo to zrobić, i usunąć logiki z widoku (co moim zdaniem jest lepsze w tym przypadku), a następnie związać z nią if.

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

Jeśli chcesz umieścić zarówno w bloku if można, po prostu trzeba zawierać nawiasów. Powodem tego jest to, że obserwowalne są funkcjami; nokaut pozwala je wykluczyć, jeśli używasz pojedynczego odniesienia, ale są one wymagane do "drążenia" do swoich właściwości.

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

Oto updated fiddle

+0

Dziękuję bardzo, że wygląda świetnie! To jest prawie to, czego potrzebuję. Jedną rzeczą jest to, że nie mogę uruchomić go za pomocą wtyczki mapowania, podczas gdy użyłeś zakodowanej funkcji Person. Czy możesz wskazać mi, co robię źle? jsfiddle tutaj: http://jsfiddle.net/graphicsxp/qXZjM/ – Sam

+0

faktycznie zignorować mój komentarz, to działa teraz. Po prostu musiałem ustawić właściwości selectedChild na ko.observable(). Wielkie dzięki ! – Sam

+0

jedno ostatnie pytanie: w jaki sposób zmodyfikowałbyś powiązanie if, aby szablon pokazywał tylko, jeśli istnieje co najmniej jedno dziecko dla wybranego dziecka? Próbowałem ko, jeśli: selectedChild && selectedChild.children.length> 0, ale to nie działa .... Jakiś pomysł? – Sam