Подтвердить что ты не робот

Рекурсивный шаблон с нокаутом js

Можно ли создать рекурсивный шаблон только с нокаутом js?

У меня есть объект нокаута:

function FormElementNode(children, text, value) {
   var self = this;
   self.children = ko.observableArray(children);
   self.text = ko.observable(text);
   self.value = ko.observable(value);
}   

children - это массив FormElementNode.

Я хочу нарисовать его, и он рекурсивно решает в узлах списка иерархии:

<ul>
   <li>Parent text value:
      Children: 
      <ul>
         <li>Child1 text value</li>
         <li>Child2 text value</li>
   </li>

Спасибо!

4b9b3361

Ответ 1

Да KnockOut поддерживает рекурсивные шаблоны, чтобы вы могли ссылаться и отображать один и тот же шаблон внутри шаблона.

Пример html в вашем случае будет выглядеть так:

<script id="formElementNodeTemplate" type="text/html">
<ul>
    <li>Parent <span data-bind="text: text"></span> 
               <span data-bind="text: value"></span>
        <br/>
        Children:
        <!-- ko template: { name: 'formElementNodeTemplate',  
                            foreach: children } -->
        <!-- /ko -->        
     </li>
   </ul>
</script>    

<div data-bind="template: { name: 'formElementNodeTemplate', data: $data }">
</div>

Демо JSFiddle.

Ответ 2

Я думаю, у меня есть небольшое лучшее решение с без корня дерева. Пожалуйста, посмотрите:

http://jsfiddle.net/nonsense66/Bzekr/

Шаблон:

<script id="treeElement" type="text/html">
    <li>
        <span data-bind="text: name"></span>
        <ul data-bind="template: { name: 'treeElement', foreach: children }">
        </ul>
     </li>
</script>    

<ul data-bind="template: { name: 'treeElement', foreach: $data.treeRoot }"></ul>

JavaScript:

var viewModel = {
    treeRoot: ko.observableArray()
};

var TreeElement = function(name, children) {
   var self = this;
   self.children = ko.observableArray(children);
   self.name = ko.observable(name);
}

var tree = [
    new TreeElement("Russia", [
        new TreeElement("Moscow")
    ]),
    new TreeElement("United States", 
    [
        new TreeElement("New York", [ 
            new TreeElement("Harlem"),
            new TreeElement("Central Park")
        ]) 
    ])
];

viewModel.treeRoot(tree);

ko.applyBindings(viewModel);

Надеюсь, что это поможет!

Ответ 3

Этот пост очень помог мне. Я всегда нахожу новые способы использования нокаута. Я просто хотел добавить одну полезную модификацию, которая делает именно то, что предложил nemesv только с помощью плагина ko.mapping.

//Nested javascript object:
var formElementNode = {
    children: [{
        children: [],
        text: 'Child1',
        value: 'Value1'
    }, {
        children: [{
            children: [{
                children: [],
                text: 'Child2.1.1',
                value: 'Value2.1.1'
            }],
            text: 'Child2.1',
            value: 'Value2.1'
        }],
        text: 'Child2',
        value: 'Value2'
    }, {
        children: [],
        text: 'Child3',
            value: 'Value3'
    }],
    text: 'Main',
    value: 'MainValue'
};

//Use ko.mapping to generate viewModel:
var viewModel = ko.mapping.fromJS(formElementNode);
ko.applyBindings(viewModel);

Как показано в этом jsFiddle.

Ответ 4

Рекурсивная пользовательская привязка

Другое решение, прочитав, что шаблоны были медленнее, я смотрю на рекурсивную привязку.

<ul data-bind="nestMe: name"></ul>

ko.bindingHandlers.nestMe = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {

    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var observable = valueAccessor() || { };
        var unwrapped = ko.unwrap(observable);

        ko.utils.setHtml(element, '<li>'+unwrapped+'<ul data-bind="foreach: children"><li data-bind="nestMe: name" /></ul></li>');

    }
};

var rootModel = function(name, children) {
    this.name = ko.observable(name);
    this.children = ko.observableArray(children);
};

var basemodel = new rootModel('test');
basemodel.children.push(new rootModel('aaa',[new rootModel('111'),new rootModel('222')]));
basemodel.children.push(new rootModel('bbb'));
basemodel.children.push(new rootModel('ccc',[new rootModel('333'),new rootModel('444')]));

ko.applyBindings(basemodel);

Имея возможность играть с данными до рекурсии, вам пригодится.

JSFiddle