Answered by:
dataBinding two controls in HTML Client

Question
-
Hi,
I'm building an addAndEdit screen that has a modal picker for a 'Source' property, which has a 'Country' navigation property.
What I'd like to do is, everytime a Source is selected, display the associated Country in a Summary control type. Country is a property as well, so I need to bind the value, not just displaying it.
I tried this, provided AddEditEntity is the screen's name:
myapp.AddEditEntity.Country_postRender = function (element, contentItem) { contentItem.dataBind("screen.Entity.Source.Country", function (value) { $(element).text(value); }); };
but when I select a Source, Country displays [object Object].Other way to do it would be adding a changeListener to Source, but I didn't know how to do the binding.
Wednesday, June 11, 2014 9:11 PM
Answers
-
Inspecting value show it is undefined.
I tried binding not to a navigation property, but to the Source value itself, and it still shows [object Object]
myapp.AddEditEntity.Country_postRender = function (element, contentItem) { contentItem.dataBind("screen.Entity.Source", function (value) { $(element).text(value); }); };
A question remains, does "value" in this callback function's argument contain the correct navigation property data for the associated Country entity when your breakpoint is hit and inspected? If so, assign the contentItem.value = value.<CountryProperty>.
If it is not there, LightSwitch lazy loading may be the underlying reason. In that case, use LightSwitch's built-in dependency injection method getCountry() to retrieve it.
The code might look something as follows:
contentItem.dataBind("screen.Entity.Source", function(newValue) { newValue.getCountry().then(function(country) { return contentItem.value = country || "No country listed."; }); });
- Marked as answer by Nicolás Lope de Barrios Friday, June 13, 2014 2:49 PM
- Unmarked as answer by Nicolás Lope de Barrios Wednesday, July 23, 2014 2:07 PM
- Marked as answer by Nicolás Lope de Barrios Thursday, July 24, 2014 1:51 AM
Friday, June 13, 2014 3:57 AM -
I tried your solution and found it works if Country is a Details Picker or Rows Layout, but not if Country is a Summary Control.
contentItem.value = country;
Easiest fix is to change to Rows Layout containing only Name.
It would be nice to get an explanation as to why the change with msls 2.5.
HTH,
Josh
- Marked as answer by Nicolás Lope de Barrios Thursday, July 24, 2014 1:51 AM
Thursday, July 24, 2014 12:11 AM
All replies
-
Try putting a breakpoint to trigger inside the dataBind function and look at the properties of value for the individual property you're looking to display in the element's text node.
It seems though that if you want to databind to a change in the Source property, that the first string argument for the dataBind function should be "screen.Entity.Source," then a callback function to set contentItem.value based on the particular Source value.
Thursday, June 12, 2014 4:52 AM -
Inspecting value show it is undefined.
I tried binding not to a navigation property, but to the Source value itself, and it still shows [object Object]
myapp.AddEditEntity.Country_postRender = function (element, contentItem) { contentItem.dataBind("screen.Entity.Source", function (value) { $(element).text(value); }); };
any suggestions?
Thursday, June 12, 2014 2:42 PM -
It seems though that if you want to databind to a change in the Source property, that the first string argument for the dataBind function should be "screen.Entity.Source," then a callback function to set contentItem.value based on the particular Source value.
Thanks Bobby,
What would be the code for that callback function?
Thursday, June 12, 2014 2:44 PM -
Hi Nico,
LittleBobby's advice is spot on.
The dataBind method basically looks for a change in the property specified in the first argument (binding path) then executes the code specified in the second argument (callback function) passing the newValue of the changed prop as argument.
You want to look for a change on "screen.Entity.Source" property and then set the value of screen.Entity.Country = newValue.Country
Also, since the code is running in the postRender of Country, screen.Entity.Country is represented by the variable contentItem, thus
contentItem.value = newValue.Country
Try this:
myapp.AddEditEntity.Country_postRender = function (element, contentItem) { contentItem.dataBind("screen.Entity.Source", function (newValue) { if (newValue){contentItem.value = newValue.Country;} }); };
Lastly, contentItem.value is a javascript object, that's why you see [object Object] when you set the text of the element. Setting the value of an entity property is different than a Custom Control Computed Property. In the former, you set contentItem.value and LS does the rendering - in the latter, you do the rendering by setting the .text() of an element, for example.
Hopefully that makes sense. Joe Binder does a good intro to dataBind here:
HTH,
Josh
Friday, June 13, 2014 2:16 AM -
Inspecting value show it is undefined.
I tried binding not to a navigation property, but to the Source value itself, and it still shows [object Object]
myapp.AddEditEntity.Country_postRender = function (element, contentItem) { contentItem.dataBind("screen.Entity.Source", function (value) { $(element).text(value); }); };
A question remains, does "value" in this callback function's argument contain the correct navigation property data for the associated Country entity when your breakpoint is hit and inspected? If so, assign the contentItem.value = value.<CountryProperty>.
If it is not there, LightSwitch lazy loading may be the underlying reason. In that case, use LightSwitch's built-in dependency injection method getCountry() to retrieve it.
The code might look something as follows:
contentItem.dataBind("screen.Entity.Source", function(newValue) { newValue.getCountry().then(function(country) { return contentItem.value = country || "No country listed."; }); });
- Marked as answer by Nicolás Lope de Barrios Friday, June 13, 2014 2:49 PM
- Unmarked as answer by Nicolás Lope de Barrios Wednesday, July 23, 2014 2:07 PM
- Marked as answer by Nicolás Lope de Barrios Thursday, July 24, 2014 1:51 AM
Friday, June 13, 2014 3:57 AM -
Josh explanation couldn't be more clearer and LittleBobbyTables was spot on with his code: LS lazy loading was the underlying reason.
Here's the final code, I had to wrap the promise line with an if (newValue) because otherwise it throws an error when adding a new record.
myapp.AddEditEntity.Country_postRender = function (element, contentItem) { // bind to the Source's Country contentItem.dataBind("screen.Enity.Source", function (newValue) { if (newValue) { newValue.getCountry().then(function (country) { return contentItem.value = country || "Country not listed."; }); } }); };
I can't thank you enough for replying and your contributions to the LS forum. Something that is so simple in the desktop client it's a bit tricky in the HTML. No wonder Michael Washington lists data binding at the top of the things to know about HTML Client. It's a whole different ballgame. I do not consider myself a bright coder but I did my research and read the articles pointed, but found most of them a bit confusing. I wish there were more code samples of simple situations like this. The HTML Client API Reference definitely needs improvement on this topic, IMHO.
Best regards,
@nlopedebarrios
- Edited by Nicolás Lope de Barrios Friday, June 13, 2014 2:51 PM
Friday, June 13, 2014 2:49 PM -
Hi,
After upgrading to msls-2.5.0 this code is not working properly, it returns 'object Object' again. Inspecting the dataBinding, I found that newValue.getCountry() is not available anymore. Any idea why and how can be fixed?
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.- Edited by Nicolás Lope de Barrios Wednesday, July 23, 2014 2:07 PM
Tuesday, July 22, 2014 11:20 PM -
Putting a breakpoint on
return contentItem.value = country;
and inspecting country, it shows that the data is in country.details._
But the control displays [object Object] anyway.
As I said, this was working properly before upgrading from msls-2.0.0 to msls-2.5.0. What changed?
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Wednesday, July 23, 2014 2:15 PM -
... No wonder Michael Washington lists data binding at the top of the things to know about HTML Client. It's a whole different ballgame. I do not consider myself a bright coder but I did my research and read the articles pointed, but found most of them a bit confusing.
Wednesday, July 23, 2014 4:28 PM -
Looking forward to it, Michael! I didn't mean "your" articles, but in a general way.
BTW, any idea how to fix this issue?
thank you.
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Wednesday, July 23, 2014 4:31 PM -
Looking forward to it, Michael! I didn't mean "your" articles, but in a general way.
BTW, any idea how to fix this issue?
thank you.
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Yikes! Thanks for the scare you just gave me! :) :)
I am about to go to press with a book that has code like yours and I'm like WT..! :)
Anyway, I just confirmed that I can upgrade to msls 2.5.0 and this code still works:
// Call getCustomers screen.getCustomers().then(function (result) { var index = result.data.length; // gets length of the full Customer array // The last Customer found in the // collection will be // set to LatestLoadedCustomer screen.LatestLoadedCustomer = result.data[index - 1]; // compensate for 0-based index // Show the Popup to display // LatestLoadedCustomer screen.showPopup("LatestCustomer"); });
See:
Wednesday, July 23, 2014 6:13 PM -
Thank you ADefwebserver. Still not working.
I tried
contentItem.value = country.data; contentItem.value = country.value; contentItem.value = country.details._.Name; //(yikes)
The first two are undefined, the last one displays the country name, but a validation error is thrown because it expects a Country Entity, not only its Name property.
This should be so simple! I'm really frustrated.
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Wednesday, July 23, 2014 7:26 PM -
Wednesday, July 23, 2014 7:46 PM
-
You may have done this already, but also try without the 'return' and conditional or ||
just:
contentItem.value = country;
If these suggestions don't work then, out of curiosity try switching the binding around like so:
myapp.AddEditEntity.Source_postRender = function (element, contentItem) { // listen to Source.value change then set Country contentItem.dataBind("value", function (newValue) { if (newValue) { newValue.getCountry().then(function (country) { contentItem.screen.findContentItem("Country").value = country; }); } }); };
HTH,
Josh
- Edited by joshbooker Wednesday, July 23, 2014 8:02 PM
Wednesday, July 23, 2014 7:56 PM -
try:
contentItem.value = country.data[0];
I tried, but data is undefined.Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Wednesday, July 23, 2014 8:08 PM -
Thank you Josh, I tried both with no luck. Before your suggestion, I tried switching the binding around, using:
screen.Source.Country = country
insted of
contentItem.screen.findContentItem("Country").value = country;
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Wednesday, July 23, 2014 8:20 PM -
Yeah but did you try using Source_postRender instead of Country_postRender like my code?Wednesday, July 23, 2014 9:22 PM
-
Yeah but did you try using Source_postRender instead of Country_postRender like my code?
Yes, of course. Same result.
I just built a Project showing the behavior, I will post a download link in a few minutes.
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Wednesday, July 23, 2014 9:37 PM -
I have uploaded a simple VS2013 update 2 solution (sandbox.zip) which reproduces the issue I described. The user story might be silly, considering the country is already in the Source, but still, I'm intrigued.
Any help appreciated.
Regards.
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.- Edited by Nicolás Lope de Barrios Wednesday, July 23, 2014 10:10 PM
Wednesday, July 23, 2014 10:04 PM -
I tried your solution and found it works if Country is a Details Picker or Rows Layout, but not if Country is a Summary Control.
contentItem.value = country;
Easiest fix is to change to Rows Layout containing only Name.
It would be nice to get an explanation as to why the change with msls 2.5.
HTH,
Josh
- Marked as answer by Nicolás Lope de Barrios Thursday, July 24, 2014 1:51 AM
Thursday, July 24, 2014 12:11 AM -
Josh, thank you for taking the time and seeing the wood. You rock!
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Thursday, July 24, 2014 1:54 AM -
You can leave it as a Summary control as-is, and the properties are attached to country, e.g. country.Name:
Thursday, July 24, 2014 6:17 AM -
LBT,
Are you saying leave it as summary and set contentItem.value = country.Name? The Country name displays in the summary control, but the form will not save "Data Invalid" error. Same error as when you set the summary control to the country entity.
I would think you can set a summary control to the entity since the control is bound to News.Country rather than News.Country.Name. Assuming setting summary control to entity was working before upgrade. So Now I wonder what changed?
PS...Not a big fan of summary control - I find it to be a solution looking for a problem. Especially in details picker - I can't stand being restricted to displaying summary property. </rant>
TIA,
Josh
Thursday, July 24, 2014 10:47 AM -
Thank you guys for your support.
Later today, I will upload another sample solution (in a different post) regarding a much serious issue: custom controls not rendering after re-opening a screen. I wrote about it at the end of this post.
Regards.
Nicolás Lope de Barrios
If you found this post helpful, please "Vote as Helpful". If it actually answered your question, please remember to "Mark as Answer". This will help other people find answers to their problems more quickly.Thursday, July 24, 2014 11:55 AM