Рекурсивный шаблон с нокаутом 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>
Спасибо!
Ответы
Ответ 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