locked
HTML Client Computed Property RRS feed

Answers

  • Hey Dave,

    After a closer look at your code I'm going to make a few assumptions.

    You have Course Entity related to Schedule Entity...one Course to many Schedules.  You're working on a Browse Screen based on Schedule Entity called ViewSchedule.  If all this is correct then you're really close. 

    First, if you have a screen property called CourseInfo then delete it from the layout and from the data (left-pane) and delete your CourseInfo_postRender code. 

    Now, on the layout, right click on the details tab and choose 'add custom control'

    On the Add Custom Control dialog type 'Schedule' - Full Path should say 'Screen.Schedule' - Click OK

    Rename the CustomControl to 'CourseInfo' and move to where you'd like

    In Properties pane click Edit Render Code and then paste this:

    myapp.ViewSchedule.CourseInfo_render = function (element, contentItem) {
        // Write code here.
        var div = $("<div id='" + contentItem.displayName + "' class='computed' ></div>");
        $(div).appendTo($(element));
    
        contentItem.dataBind("value.Course.Number", function (newValue) {
            div.text(CourseInfo_Compute(contentItem));
        });
        contentItem.dataBind("value.Course.Name", function (newValue) {
            div.text(CourseInfo_Compute(contentItem));
        });
    };
    function CourseInfo_Compute(contentItem) {
        var Me = contentItem.value; var result;
        result = Me.Course.Number + " " + Me.Course.Name;
        //alert(result);
        return result;
    
    };

    If assumptions correct then that should do it.

    HTH,

    Josh



    • Edited by joshbooker Wednesday, April 30, 2014 9:35 PM
    • Marked as answer by DaveBarker19 Thursday, May 1, 2014 12:33 AM
    Wednesday, April 30, 2014 9:33 PM

All replies

  • I don't unfortunately know of another example, but essentially he is creating a "screen property" that serves as the "computed property" and uses the _postRender() method of that property (after having added it to the visual designer) to compute and display the value. He also proposes a different method using a RIA domain service.

    Depending on how and where you want to use/display the computed property, you don't have to do it in the _postRender(). As long as you have a hook into setting the value of the screen property (e.g. in the _created event of the screen) then you should be able to avoid having to worry about the _postRender event.

    I assume you know how to write the code that looks at the child entities to compute the overall value.

    Otherwise you must provide more information about exactly where/how you want to show it.


    Regards, Xander. My Blog

    Tuesday, April 29, 2014 9:40 PM
  • Thanks Xander,

    I guess my problem is that I'm not really a developer :) so assuming that I know is probably not a good idea. I have a working application using the Silverlight client that is great. I'm just trying to convert it to the HTML client.

    If I created a computed property for use in the Silverlight client it would look like this.

    Namespace LightSwitchApplication
        Public Class Schedule
            Private Sub CourseInfo_Compute(ByRef result As String)
                ' Set result to the desired field value
                result = Course.Number + " " + Course.Name
            End Sub
        End Class
    End Namespace

    I just can't make out from Michael's example how to duplicate this?

    I have created a string property on the screen named courseInfo and I am editing the postRender event but not sure what to put there.

    Thanks


    Dave Barker

    Wednesday, April 30, 2014 3:08 PM
  • This may help, because it is not just a case to show the computed property, but you will need to have it update when the underlying data is updated:

    Writing JavaScript / The Binding Pattern


    Unleash the Power - Get the LightSwitch HTML Client book

    http://LightSwitchHelpWebsite.com

    Wednesday, April 30, 2014 3:52 PM
  • Michael is correct you'll need to use binding to keep the computed value refreshed.  If you're having trouble puting it all together then maybe this will help. Rather than a screen property, I'd simply use a CustomControl and do the calculation & binding in the _render method.  Your code will be something like this:

    myapp.myScreenName.CourseInfo_render = function (element, contentItem) {
        var div = $("<div id='" + contentItem.displayName + "' class='computed' ></div>");
        $(div).appendTo($(element));
    
        contentItem.dataBind("value.Course.Number", function (newValue) {
            div.text(CourseInfo_Compute(contentItem));
        });
        contentItem.dataBind("value.Course.Name", function (newValue) {
            div.text(CourseInfo_Compute(contentItem));
        });
    };
    
    function CourseInfo_Compute(contentItem) {
        var Me = contentItem.value; var result;
        result = Me.Course.Number + " " + Me.Course.Name;
        //alert(result);
        return result;
    };

    Notes:  Change 'myScreenName' to yours.  The binding path is relative to what you select for data binding when you add the CustomControl to the layout.  I think in the code above, binding the CustomControl to the screen (assuming it's an add\edit screen for 'Course' entity) will work.  If not, then change the binding path "value.Course.Name" until you get it right.  Setting breakpoints in _render function and inspecting contentItem can help with this.

    You could put the calculation (Me.Course.Number + " " + Me.Course.Name;) directly in the dataBind calls, but I prefer to break it out so the calculation is as-similar-as-possible to the vb compute code and I only have to change it in one place.

    HTH,

    Josh



    • Edited by joshbooker Wednesday, April 30, 2014 5:22 PM
    Wednesday, April 30, 2014 5:18 PM
  • Josh and Michael

    First thanks for you help

    Second I am definitely having a problem with the binding. I have tried setting and breakpoint but unfortunately am not able to make any sense of what I'm seeing.

    This is what I have so far

    /// <reference path="~/GeneratedArtifacts/viewModel.js" />
    
    myapp.ViewSchedule.Details_postRender = function (element, contentItem) {
        // Write code here.
        var name = contentItem.screen.Schedule.details.getModel()[':@SummaryProperty'].property.name;
        contentItem.dataBind("screen.Schedule." + name, function (value) {
            contentItem.screen.details.displayName = value;
        });
    }
    
    myapp.ViewSchedule.CourseInfo_postRender = function (element, contentItem) {
        // Write code here.
        var div = $("<div id='" + contentItem.displayName + "' class='computed' ></div>");
        $(div).appendTo($(element));
    
        contentItem.dataBind("value.course.number", function (newValue) {
            div.text(CourseInfo_Compute(contentItem));
        });
        contentItem.dataBind("value..Course.Name", function (newValue) {
            div.text(CourseInfo_Compute(contentItem));
        });
    };
    
    function CourseInfo_Compute(contentItem) {
        var Me = contentItem.value; var result;
        result = Me.Course.Number + " " + Me.Course.Name;
        //alert(result);
        return result;
    
    };
    Error Message
     

    Thank again for your help


    Dave Barker

    Wednesday, April 30, 2014 7:57 PM
  • Hi Dave,

    The code assumes you're on an add\edit screen for the Course entity.  Since the binding paths are relative we need to know more about your entities \ screens.

    From looking at your vb code and your js I suspect you're on a screen for the Schedule entity which may have a related entity called Course.  Please tell us more about your entities and type of screen etc. 

    Perhaps screen shots would help, too.

    Josh


    • Edited by joshbooker Wednesday, April 30, 2014 8:35 PM
    Wednesday, April 30, 2014 8:34 PM
  • Hey Dave,

    After a closer look at your code I'm going to make a few assumptions.

    You have Course Entity related to Schedule Entity...one Course to many Schedules.  You're working on a Browse Screen based on Schedule Entity called ViewSchedule.  If all this is correct then you're really close. 

    First, if you have a screen property called CourseInfo then delete it from the layout and from the data (left-pane) and delete your CourseInfo_postRender code. 

    Now, on the layout, right click on the details tab and choose 'add custom control'

    On the Add Custom Control dialog type 'Schedule' - Full Path should say 'Screen.Schedule' - Click OK

    Rename the CustomControl to 'CourseInfo' and move to where you'd like

    In Properties pane click Edit Render Code and then paste this:

    myapp.ViewSchedule.CourseInfo_render = function (element, contentItem) {
        // Write code here.
        var div = $("<div id='" + contentItem.displayName + "' class='computed' ></div>");
        $(div).appendTo($(element));
    
        contentItem.dataBind("value.Course.Number", function (newValue) {
            div.text(CourseInfo_Compute(contentItem));
        });
        contentItem.dataBind("value.Course.Name", function (newValue) {
            div.text(CourseInfo_Compute(contentItem));
        });
    };
    function CourseInfo_Compute(contentItem) {
        var Me = contentItem.value; var result;
        result = Me.Course.Number + " " + Me.Course.Name;
        //alert(result);
        return result;
    
    };

    If assumptions correct then that should do it.

    HTH,

    Josh



    • Edited by joshbooker Wednesday, April 30, 2014 9:35 PM
    • Marked as answer by DaveBarker19 Thursday, May 1, 2014 12:33 AM
    Wednesday, April 30, 2014 9:33 PM
  • Josh,

    Your assumptions are correct and that does work. Know I just need to see if I can understand what you are doing here so that I can reproduce the result.

    Again thank you.


    Dave Barker

    Thursday, May 1, 2014 12:33 AM
  • Hi Dave. Glad it works. Basically the custom control renders a div and the dataBind sets the text of the div by 'listening' for a change on the object specified by the binding path "value.Course.Number". When the prop changes, the callback function executes to set the div text. Since your computation uses two properties you must bind to both. Using a separate function to return the result is just a personal preference as you could have put the concatination into both dataBind calls directly instead. The trickiest part about binding is getting the path right since its relative to the data to which you bound the content control (screen.Schedule) and also relative to the type of screen (browse or add/edit) - and property (single or collection ). Yours was bound to Schedule so contentItem.value is the Shedule property on the screen thus contentItem.value.Course.Name is the name prop of the Course navigation prop of the schedule prop. Pretty sure I stopped making coherent sentences a while before this one.
    • Edited by joshbooker Thursday, May 1, 2014 1:09 AM
    Thursday, May 1, 2014 12:59 AM
  • Hi Dave. Glad it works. Basically the custom control renders a div and the dataBind sets the text of the div by 'listening' for a change on the object specified by the binding path "value.Course.Number". When the prop changes, the callback function executes to set the div text. Since your computation uses two properties you must bind to both. Using a separate function to return the result is just a personal preference as you could have put the concatination into both dataBind calls directly instead. The trickiest part about binding is getting the path right since its relative to the data to which you bound the content control (screen.Schedule) and also relative to the type of screen (browse or add/edit) - and property (single or collection ). Yours was bound to Schedule so contentItem.value is the Shedule property on the screen thus contentItem.value.Course.Name is the name prop of the Course navigation prop of the schedule prop. Pretty sure I stopped making coherent sentences a while before this one.

    Josh, excelent contribution. Do you know where can I find an example for a computed field bind to 2 properties, for a collection (table) in a browse screen?

    cheers,

    Nico

    Wednesday, May 14, 2014 6:56 PM
  • Hey Nico,

    I assume you want to display the computed value in a table cell while the computation is based on two other properties on the same row.  I've not done this so I'm not sure if it's possible.  It's like conditional formatting in SL client grid.  That required setting the binding in a handler on the LoadingRow event.

    Like this:

    http://social.msdn.microsoft.com/Forums/vstudio/en-US/e2ffa707-285b-4334-8f07-2e0f903b3af0/databinding-of-datagridrow-button?forum=lightswitch

    Not sure if there's  a way to raise such an event for the HTML collection controls.

    Sorry, I haven't found anything...will have to try it sometime.

    Josh

    Wednesday, May 14, 2014 8:07 PM
  • Nico,

    I tried this and turns out it's much easier than I thought.  Since Browse Screens are not editable, it's not necessary to use binding at all.  I found that if I added a CustomControl to a list or table row bound to screen the following code would render the 'computed' value

    myapp.BrowseSchedules.ScreenContent_render = function (element, contentItem) {
        // Write code here.
        var div = $("<div>" + contentItem.data.Course.Number + " " + contentItem.data.Course.Name + "</div>");
        $(div).appendTo($(element));
    };

    I am surprised to see that contentItem.data is the entity from the current row.

    HTH,

    Josh


    Wednesday, May 14, 2014 11:55 PM
  • Nico,

    I tried this and turns out it's much easier than I thought.  Since Browse Screens are not editable, it's not necessary to use binding at all.  I found that if I added a CustomControl to a list or table row bound to screen the following code would render the 'computed' value

    myapp.BrowseSchedules.ScreenContent_render = function (element, contentItem) {
        // Write code here.
        var div = $("<div>" + contentItem.data.Course.Number + " " + contentItem.data.Course.Name + "</div>");
        $(div).appendTo($(element));
    };

    I am surprised to see that contentItem.data is the entity from the current row.

    HTH,

    Josh



    Josh, thank you! you rock. It works.
    Thursday, May 15, 2014 5:45 PM
  • Josh, sorry to bother you again, but I can't find my way binding two controls. Can you please take a look at it? how would you do it?

    Thanks in advance.

    Friday, June 13, 2014 12:04 AM
  • Here's a simpler way to do computed properties:  Simply add a _Compute method and let LS do the binding for you.

    Take a read:

    HTML Client Computed Properties

    HTH,

    Josh

    Friday, December 5, 2014 2:41 AM