Separate markup (with binding syntax) from processing in an html LightSwitch custom control.

Introduction

This post is about kind of experimental stuff.  It relies on  the brand new WinJs library.

LightSwitch uses also WinJS, but version 1.

The problem I want to solve in this post is about custom controls.

When making custom controls in LightSwitch, very often you come across code like this:

var CustomDiv = "<li tabindex='0' class='ui-li ui-btn ui-btn-up-a ui-btn-up-undefined' ";
               CustomDiv = CustomDiv + " data-msls='true' ";
                CustomDiv = CustomDiv + "onclick='editPage(" + paramPageContent.PageId + "," + chapterId + "); ";
                CustomDiv = CustomDiv + "return false' rel='external>";
                CustomDiv = CustomDiv + "<div class='msls-presenter msls-list-child ";
                CustomDiv = CustomDiv + "msls-ctl-summary msls-vauto msls-hauto ";
                CustomDiv = CustomDiv + "msls-compact-padding msls-leaf msls-presenter-content ";
                CustomDiv = CustomDiv + "msls-font-style-normal'>";
                CustomDiv = CustomDiv + "<div class='msls-text-container'>";
                CustomDiv = CustomDiv + "<span class='id-element'>" + shortText + "</span>";
                CustomDiv = CustomDiv + "</div>";
                CustomDiv = CustomDiv + "</div>";
                CustomDiv = CustomDiv + "<div class='msls-clear'></div>";
                CustomDiv = CustomDiv + "</li>";

 

Wouldn’t it be much nicer if the markup could be placed in a dedicated html file with “normal” html syntax like this:

<div>
    Hi,
    <span data-win-bind="innerText: FirstName Binding.Mode.twoway"></span>
    <span>  </span>
    <span data-win-bind="innerText: LastName Binding.Mode.twoway"></span>
    <br />
    <hr />
    <input type="text" data-win-bind="value: LastName Binding.Mode.twoway" placeholder="Last name" />
    <input type="text" data-win-bind="value: FirstName Binding.Mode.twoway" placeholder="First name" />
</div>

 

We’ll elaborate here an experimental approach. See the disclaimer in the conclusion section !  I tried unsuccessfully  to find the forum post, but I recall that Html rock stars Josh Booker and LittleBobyTables did similar things as in this post.

the solution

First acquire WinJs version 3 from here. Use the direct download because the nuget package isn’t working (for the moment).

I added it as follows in the HtmlClient project:

solution

 

 

Update the script reference in default.html

<script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"></script>
    <script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/globalize/0.1.1/globalize.min.js"></script>
    <!--<script type="text/javascript" src="Scripts/winjs-1.0.min.js"></script>-->
    <script src="scripts/winjs/js/winjs.js"></script>
    <script type="text/javascript" src="Scripts/jquery-1.9.1.min.js"></script>
    <script type="text/javascript" src="Scripts/jquery.mobile-1.3.0.min.js"></script>
    <script type="text/javascript" src="Scripts/datajs-1.1.1.min.js"></script>
    <script type="text/javascript" src="Scripts/Generated/resources.js"></script>
    <script type="text/javascript" src="Scripts/msls-2.5.1.min.js"></script>
    <script type="text/javascript" src="Scripts/Generated/generatedAssets.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            msls._run()
            .then(null, function failure(error) {
                alert(error);
            });
        });
    </script>
</body>
</html>

As you can see version one of WinJs is replaced by version 3 !

Let’s create our first html fragment for the custom control

 

fragemnt

 

So make inside the Html client a folder called templates (you can name it whatever you want) and create inside that folder a new html file with following content:

<div>
    Hi,
    <span data-win-bind="innerText: FirstName Binding.Mode.twoway"></span>
    <span>  </span>
    <span data-win-bind="innerText: LastName Binding.Mode.twoway"></span>
    <br />
    <hr />
    <input type="text" data-win-bind="value: LastName Binding.Mode.twoway" placeholder="Last name" />
    <input type="text" data-win-bind="value: FirstName Binding.Mode.twoway" placeholder="First name" />
</div>

 

As you can see, pure markup with declarative binding syntax, specific to WinJS.

The LightSwitch custom control handling

myapp.AddEditCustomer.Customer_render = function (element, contentItem) {
    WinJS.UI.Fragments.renderCopy("/HtmlClient/templates/fragment.html", $(element)[0])
            .done(
                function () {
                    contentItem.dataBind("value.FirstName", function (newvalue) {
                        WinJS.Binding.processAll($(element)[0], contentItem.value);
                    });
                    contentItem.dataBind("value.LastName", function (newvalue) {
                        WinJS.Binding.processAll($(element)[0], contentItem.value);
                    });
                }
            );
};

 

Don’t worry, the html fragment will be retrieved from the server only once (the first time it is needed). Exactly in the same way how e.g. Angular would treat views. It’s clear that the renderCopy method from WinJS is doing here the heavy lifting.

The last piece of infrastructure code

In order to have working data binding between the html fragment and the javascript objects containing the backing data you need to execute once following code block:

WinJS.Namespace.define("Binding.Mode", {
        twoway: WinJS.Binding.initializer(function (source, sourceProps, dest, destProps) {
            WinJS.Binding.defaultBind(source, sourceProps, dest, destProps);
            dest.onchange = function () {
                var d = dest[destProps[0]];
                var s = source[sourceProps[0]];
                if (s !== d) source[sourceProps[0]] = d;
            }
        })
    });

So, only put once this code fragment in your code base. No need to repeat this per custom control !

 

Conclusion

Try the above and check if it works for you, but don’t start using is for production projects.

I have no clue at all if using version 3 of winJs in LightSwitch causes side effects. We’ll await the feedback in the LightSwitch forum.