JsViews, how to bind data to the root object, as well as to its attached properties?

Do I experience strange behaviors when the data that connects an object to a form makes me question what exactly is related to the data?

Basically, I have a form that creates new companies and also updates them. The actual creation / update is done through ajax, so I use the same form for both purposes. In the case when I need to create a company, everything works as I expect. However, when I have to update the company, everything is not the way I expect them. Please read the following code.

Here is my HTML form example:

<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 entering a form showing "Company ABC", it is empty. However, if I enter anything into it, the value of Company.Name changes! But while I want the input to be bound to the Name property of my Company object, I also want it to be aware of any changes made to the (parent) Company object and update the data binding to it. Name property, respectively.

So my question is, how do I change the way I write this code so that I can achieve data binding to both the root object and the property?

+6
source share
2 answers

The problem you ran into was that in your script you have paths, such as Company.Name , for which you want to bind data to changes not only in the sheet property, but also in changes related to replacing the objects above in the path (in this case, the Company).

To do this, you need to use the syntax data-link="Company^Path" .

See the "Ways" section: sheet changes or profound changes to this documentation topic: http://www.jsviews.com/# observe@deep .

See also examples, such as Example: JsViews with regular objects and an array in this section: http://www.jsviews.com/#explore/objectsorvm .

Here is an update to your jsfiddle using this syntax: https://jsfiddle.net/msd5oov9/2/ .

BTW, FWIW, in your fix using {^{for}} you did not need to use the second template - you could also write:

 <form class="form-horizontal"> {^{for Company}} ... <input type="text" data-link="Name" /> {{/for}} </form> 

To answer your subsequent question in your comment below, you can associate any "block" tag with a template. Using tmpl=... in the tag means that you decide to split the contents of the block into a separate reusable template. ("Partially" if you want). The data context for this template will be the same as in the block.

Thus, the {{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 can use either {^{for Company tmpl=.../}} or {{include tmpl=.../}} , but in the second case, your other template that you reference will use <input type="text" data-link="Company^Name" /> , not <input type="text" data-link="Name" /> .

Here are some relevant links:

+3
source

I discovered one way to achieve this. It may seem complicated at first, but it will make sense as soon as you understand it correctly.

(PS: I wish there was such an example. I could just write about it.)

HTML markup:

 <script type="text/x-jsrender" id="CompanyFormTemplate"> <form> {^{for Company tmpl="#CompanyDetailsTemplate" /} </form> </script> <script type="text/x-jsrender" id="CompanyDetailsTemplate"> <input type="text" data-link="Name" /> </script> 

Javascript: no changes required from the above code.


Well, as I said, the solution may look complicated, but it turned out that I really needed to set the data binding first to the Company object, and then to the property objects. I wonder if there is a more elegant solution (that is, one in which all this can be achieved in one template), but this solution ensures that data binding occurs both on the parent object and on its properties.

I published JsFiddle for this solution, so if anyone encounters this problem and wants to understand how this solution will work their particular problem, they will be able to play with a working solution.

+1
source

Source: https://habr.com/ru/post/987480/


All Articles