I am experiencing odd behavior when data linking an object to a form that led me to re-question what exactly is being data bound?
Basically I have a form that creates new Companies as well as updates them. The actual creation/update is done via ajax, which is why I am using the same form for both purposes. In the case when I have to create a company, everything works as I expect. However when I have to update a company, things don't work like how I expect them to. Please have a look at the following code.
Here is my sample Form HTML:
<div id="result"></div>
<script type="text/x-jsrender" id="CompanyFormTemplate">
<form>
<input type="text" data-link="Company.Name" />
</form>
</script>
Here is my Javascript code:
var app = new CompanyFormContext();
function CompanyFormContext() {
this.Company = {
Name: ''
};
this.setCompany = function (company) {
if (company) {
$.observable(this).setProperty('Company', company);
}
};
};
$(function () {
initPage();
...
if (...) {
// we need to update company information
app.setCompany({ Name: 'Company ABC' });
}
});
function initPage() {
var template = $.templates('#CompanyFormTemplate');
template.link("#result", app);
}
Instead of the form input showing 'Company ABC', it is empty. However if I enter anything in it, then the Company.Name value does change! But while I want the input to data bind to Name property of my Company object, I also want it to be aware of any changes made to the (parent) Company object and update it's data binding to it's Name property accordingly.
So my question is how should I change the way I am writing this code so that I can achieve a data bound both on the root object as well as the property?
The issue you were having was because in your scenario, you have paths like Company.Name
for which you want to data-link to changes not only of the leaf property but also to changes involving replacing objects higher up in the path (in this case the Company).
For that you need to use the syntax data-link="Company^Path"
.
See the section Paths: leaf changes or deep changes in this documentation topic: http://www.jsviews.com/#observe@deep.
See also the examples such as Example: JsViews with plain objects and array in this topic: http://www.jsviews.com/#explore/objectsorvm.
Here is an update of your jsfiddle, using that syntax: https://jsfiddle.net/msd5oov9/2/.
BTW, FWIW, in your fix using {^{for}}
you didn't have to use a second template - you could alternatively have written:
<form class="form-horizontal">
{^{for Company}}
...
<input type="text" data-link="Name" />
{{/for}}
</form>
To respond also to your follow-up question in your comment below, you can associate any 'block' tag with a template. Using tmpl=...
on the tag means you have decided to separate what would have been the block content into a separate re-usable template. (A 'partial', if you will). The data context for that template will be the same as it would have been within the block.
So specifically, {{include}} {{if}} and {{else}} tags do not move the data context, but {{for}} and {{props}} do. With custom tags you can decide...
So in your case you could use either {^{for Company tmpl=.../}}
or {{include tmpl=.../}}
but in the second case your other template that you reference would use <input type="text" data-link="Company^Name" />
rather than <input type="text" data-link="Name" />
.
Here are some relevant links:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With