问题
New to knockout and loving it so far cut a 700 line jQuery mess into 150 lines. The one part I am not really liking is the templating. I want to be able to create a file similar to this
module.ViewModel.views = {
'view1' : '<div data-bind="foreach: data">TEMPLATE</div>'
};
// in my view model set something like
ViewModel.view1Template = module.ViewModel.views.view1;
// then in my html have
<div data-bind="template: view1Template()"></div>
I would like to be able to do this possibly with mustache if that matters but really I just want to add reusability to my templates not a fan of having them referenced by IDs directly in the html. The other reason I would like to do this is in my views folder I have other templates that use mustache but not knockout would like to keep my formatting consistent across all JS templates.
UPDATE
The answer below seems like currently the closest thing to what I want to do I did it slightly different
for (var view in module.views){
var node = $("<script/>", {
"type" : "text/html",
"id" : view,
"text" : module.views[view]
}).appendTo("body");
}
回答1:
You can insert the elements into the DOM dynamically and apply the ko binding afterwards:
var html = $.parseHtml(module.ViewModels.views['view1'])[0];
ko.applyBindings(model, html);
$('#content').append(html);
Live demo
http://jsfiddle.net/bikeshedder/VHUcF/
I just realized that I might have answered only half of your question. Sadly the template binding handler only accepts an element id
as argument and no elements. This however is easy to fix by adding the templates to the DOM before applying the bindings:
HTML
<script id="templates" type="text/html"></script>
<div id="content" data-bind="template: templates.answerList.id"></div>
JavaScript
var templates = {
answerList: '<ul class="answer-list" data-bind="template: { name: templates.answer.id, foreach: answers }"></ul>',
answer: '<div class="answer" data-bind="text: text"></div>'
};
// insert templates into DOM
for (var name in templates) {
var html = templates[name];
var element = document.createElement('div');
$(element).append($.parseHTML(html)[0]);
element.id = 'tpl_' + name;
$(element).attr('id', element.id);
templates[name] = element;
$('#templates').append(element);
}
answerModel = {
answers: [
{ text: 1 },
{ text: 42 },
{ text: 667 }
],
templates: templates
};
ko.applyBindings(answerModel, $('#content')[0]);
Live demo
http://jsfiddle.net/bikeshedder/VHUcF/1/
回答2:
I just came up with a better solution to this problem. It no longer requires you to add a ".name" when specifying the template.
HTML
<script id="templates" type="text/html"></script>
<div id="content" data-bind="template: templates.answerList"></div>
JavaScript
var templates = {
answerList: 'Answers: <ul class="answer-list" data-bind="template: { name: templates.answer, foreach: answers }"></ul>',
answer: '<li class="answer" data-bind="text: text"></li>'
};
var templateIds = {};
for (var name in templates) {
var id = 'tpl_' + name;
$(document.createElement('div'))
.append($.parseHTML(templates[name]))
.attr('id', 'tpl_' + name)
.appendTo('#templates');
templateIds[name] = id;
}
answerModel = {
answers: [
{ text: 1 },
{ text: 42 },
{ text: 667 }
],
templates: templateIds
};
ko.applyBindings(answerModel, $('#content')[0]);
Live demo
http://jsfiddle.net/bikeshedder/VHUcF/3/
Note
This attempt requires you to either pass the templates
as model attribute or define templates
at the global scope. You can also just write "tpl_"
+ ' which I find even more natural to use.
<div data-bind="template: 'tpl_answers'"></div>
If you do not want to put the script
element containing the templates in the HTML just create it from the JavaScript as well.
来源:https://stackoverflow.com/questions/14611936/using-a-variable-to-store-a-knockout-template