Default values for missing parameters
I'm using Knockout with jQuery and jQuery templates. Assume that I have a template which expects a person object
<script type="text/html" id="person_template">
<tr><td>Forename</td><td><input type="textbox" data-bind="value:FORENAME" /></td></tr>
<tr><td>Surname</td><td><input type="textbox" data-bind="value: SURNAME"/></td></tr>
</script>
Now, if I pass an object with just a FORENAME to this template, I will get an error:
SURNAME is not defined error
I tried to create a custom binding in Knockout, but the error is thrown before it even gets there.
If I fill in these empty fields before passing the object to the template, I know everything will work out, but I would开发者_高级运维 like to have the solution in my template rather than in my javascript.
Does anyone know a method that might help for situations like these?
This is a bit challenging, because you are within a template. While preparing the template, KO accesses the variable (well, actually it is accessed in jQuery Templates by a function that KO built).
One option is to pass your property as a string to a custom binding and make sure that it is initialized.
It would be like:
ko.bindingHandlers.valueWithInit = {
init: function(element, valueAccessor, allBindingsAccessor, context) {
var value = valueAccessor();
if (!context[value]) {
context[value] = ko.observable();
}
var realValueAccessor = function() {
return context[value];
}
//call the real value binding
ko.bindingHandlers.value.init(element, realValueAccessor, allBindingsAccessor, context);
},
update: function (element, valueAccessor, allBindingsAccessor, context) {
var realValueAccessor = function() {
return context[valueAccessor()];
}
//call the real value binding
ko.bindingHandlers.value.update(element, realValueAccessor);
}
}
So, this would validate that your object has the field, if it does not it creates a new observable for that field. Then, it hands it off to the real value binding.
A very similar (but less verbose) alternative to this would be to have the binding ensure that the field is there and then rewrite the binding attribute to use the real value
binding. Something like:
//Another option: rewrite binding after making sure that it is initialized
ko.bindingHandlers.valueWithInit = {
init: function(element, valueAccessor, allBindingsAccessor, context) {
var value = valueAccessor();
if (!context[value]) {
context[value] = ko.observable();
}
$(element).attr("data-bind", "value: " + value);
ko.applyBindings(context, element);
}
}
Both of these assume that the field that you are passing is directly off of the object that is the context of your template (so, it wouldn't work if you passed something with global scope like 'viewModel.someProperty').
Here is a working sample with both options: http://jsfiddle.net/rniemeyer/dFSeB/
I would rather not pass the field as a string, but there is not really a good way around it that I see.
You'll be better off ensuring that the object passed to the template has all the parameters set in. If they are not then you can add default values but putting all this logic in the template is going against the MVVM pattern. The templates (like Views in mvc) are not supposed to contain any logic IMO.
精彩评论