You are here:   Blog
Register   |  Login

 

Dec 28

Written by: Michael Washington
12/28/2012 10:24 AM  RssIcon

image

To create responsive HTML applications (using JavaScript) you will need  to use asynchronous calls to communicate with external resources. While you can make requests synchronously, it is a bad practice because it locks up the web browser. 
 
Asynchronous code isn’t easy to write, however, there are patterns that make it easier. In .NET there are classes like Task<T>  that allows you to await on asynchronous code. This code is easier to write because it looks like synchronous code. To write asynchronous code in JavaScript, we have the Promise object. A Promise object is an object that acts as a proxy for a result that is initially unknown.

As the LightSwitch team pointed out to me:

  • In order to communicate with remote resources from code, you need to write asynchronous code.
  • Promise objects are one possible way of managing asynchronous work that LightSwitch has adopted.
  • WinJS Promise objects represent the specific implementation of Promises that the LightSwitch runtime understands.
     

Promise Objects In LightSwitch

image


In LightSwitch, Promise objects are produced by calling async methods. For example:

myapp.dataWorkspace.ApplicationData.OrdersForUser().execute()

is an async method, and it returns a Promise object.

 

image

 

We create the server side query by selecting Add Query after right-clicking on the table.

We then use the following code:

 

        partial void OrdersForUser_PreprocessQuery(ref IQueryable<PromiseOrders> query)
        {
            // Only show the Orders for the current user
            query = query.Where(x => x.UserName == this.Application.User.Identity.Name);
        }

 

image

 

We open the Screen and select the Created method.

 

image

If we try to directly call the query we find that it  does not return the expected value, instead, it returns a Promise object.

To consume the Promise object, we use the following code:

 

myapp.Main.created = function (screen) {
    myapp.activeDataWorkspace.ApplicationData.OrdersForUser().execute().then(function (results) {
        var TotalCountOfOrders = CountOrders(results);
        screen.TotalOrdersForCurrentUser = TotalCountOfOrders.toString();
    });
};
function CountOrders(Orders) {
    var TotalOrders = 0;
    var orders = Orders.results;
    orders.forEach(function (order) {
        TotalOrders = TotalOrders + 1;
    });
    return TotalOrders;
}

 

image

When we run the application, we see that the code works as expected.

 

The Then Method

image

A Promise object really only has one interesting method the then method (note: It is not recommended that you use the done method because the scenarios for its proper use is few).

With the then method, you can specify code that is called when the asynchronous work has completed (either with an error or successfully).

 

Calling The msls.promiseOperation Directly

image

We can use the msls.promiseOperation method to wrap any asynchronous call that we need to make (to maintain the most predictable coding experience, the best way to create your own Promise objects is to use the msls.promiseOperation() method).

The best examples can be found in the article: New LightSwitch HTML Client APIs (Stephen Provine) . It includes examples of importing data from remote web sites.

Let us look at an example that demonstrates how we can use this method to encapsulate async methods.

In the article, Retrieving The Current User In The LightSwitch HTML Client , we retrieved the user name of the currently logged in user, using this JQuery code:

 

    $.ajax({
        type: 'post',
        data: {},
        url: '../web/GetUserName.ashx',
        success: function success(result) {
            entity.UserName = result;
        }
    });

 

This code is not very extensible because in order to assign the result to the UserName property of the entity, the entire code must reside inside the calling method.

image

Instead, we can open the table…

image

Click the Client tab.

This switches us to the client side code that will interact with the entity (this code will be written in JavaScript and run on the client).

image

We then select the Created method.

We use the following code for the method:

 

myapp.PromiseOrders.created = function (entity) {
    // Set the default date for the Order
    entity.OrderDate = new Date();
    // Using a Promise object we can call the CallGetUserName function
    msls.promiseOperation(CallGetUserName).then(function PromiseSuccess(PromiseResult) {
        // Set the result of the CallGetUserName function to the 
        // UserName of the entity
        entity.UserName = PromiseResult;
    });
};
// This function will be wrapped in a Promise object
function CallGetUserName(operation) {
    $.ajax({
        type: 'post',
        data: {},
        url: '../web/GetUserName.ashx',
        success: operation.code(function AjaxSuccess(AjaxResult) {
            operation.complete(AjaxResult);
        })
    });
}

 

A few things to note about the code above:

  • The CallGetUserName method is passed an operation that is being set to complete in the success parameter of the JQuery Ajax call. If we do not do this the Promise operation will not know when it is complete.
  • The complete method allows us to pass an optional value to the calling method (in this case we are passing the user name retrieved).
  • The advantage of using the msls.promiseOperation in this example, is that it allows us to wrap the JQuery Ajax call. This allows us to place it in a separate method which provides for more manageable code.

 

Handling Errors

In LightSwitch, there are three things you can do regarding errors:
 

  1. Don’t handle them. In this case, the error will be silently eaten by the runtime.
  2. Pass a second function to the then method. This function will be called if there was an error.
  3. In custom screen methods, return the created Promise to the runtime. The LightSwitch runtime attaches handlers for both erroneous and successful completion, and will show any errors that occurred to the user. It will also grey out the application and show a progress indicator if the promise does not complete within a reasonable amount of time. This is the recommended approach for custom screen methods.

 

For Render Methods Use Binding

image

The best use of Promise methods is for external async calls. For LightSwitch data, you will still want to use data binding as described in the article: Writing JavaScript That Implements The Binding Pattern In Visual Studio LightSwitch.  

As the LightSwitch team pointed out to me:

In render and post render code, you almost always want to use the data binding to handle cases where data is not loaded yet. By hooking up the data binding, the initial traversal of the data binding path will cause data to start loading and at some point later, your code will be called when the data has been loaded.

For example, the following code does not work:

image

 

image

When we run the application, the associated Products have not had a chance to load so the display is blank.

Instead we use the following code that uses data binding:

 

myapp.AddEditPromiseOrders.RowTemplate_render = function (element, contentItem) {
    // We need to wait until the Products for the Order Detail are loaded
    // so we create a binding to "value.PromiseProduct.ProductName"
    // When the data is loaded the binding will be raised
    // We will then have all the data required for our display
    contentItem.dataBind("value.PromiseProduct.ProductName", function (newValue) {
        // Create a template
        var itemTemplate = $("<div></div>");
        // Get the Product name and quantity
        var ProductName = contentItem.value.PromiseProduct.ProductName;
        var ProductQuantity = contentItem.value.ProductQuantity;
        // Create the final display
        var FinalName = $("<h2>" + ProductName + ' [' + ProductQuantity + ']' + "</h2>");
        // Complete the template
        FinalName.appendTo($(itemTemplate));
        itemTemplate.appendTo($(element));
    });
};

 

image

The code now works as expected.

A Promise method could have been used, but it would not update when the values changed.

 

Special Thanks

A special thanks to LightSwitch team member Stephen Provine for his valuable assistance.

 

LightSwitch Help Website Articles

Retrieving The Current User In The LightSwitch HTML Client

Writing JavaScript That Implements The Binding Pattern In Visual Studio LightSwitch

Implementing The Wijmo Radial Gauge In The LightSwitch HTML Client

Writing JavaScript In LightSwitch HTML Client Preview

Creating JavaScript Using TypeScript in Visual Studio LightSwitch

Theming Your LightSwitch Website Using JQuery ThemeRoller

Using Toastr with Visual Studio LightSwitch HTML Client (Preview)

 

LightSwitch Team HTML and JavaScript Articles

Custom Controls and Data Binding in the LightSwitch HTML Client (Joe Binder)

Creating Screens with the LightSwitch HTML Client (Joe Binder)

The LightSwitch HTML Client: An Architectural Overview (Stephen Provine)

Writing JavaScript Code in LightSwitch (Joe Binder)

New LightSwitch HTML Client APIs (Stephen Provine)

A New API for LightSwitch Server Interaction: The ServerApplicationContext

Building a LightSwitch HTML Client: eBay Daily Deals (Andy Kung)

 

Download Code

The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx

(you must have LightSwitch HTML Client CTP4 or higher installed to run the code)

5 comment(s) so far...


Gravatar

Re: Using Promises In Visual Studio LightSwitch

Michael,
This is really a great article, especially for a Jquery dummy like me :)
thanks a lot
paul.

By paul van bladel on   12/29/2012 1:05 AM
Gravatar

Re: Using Promises In Visual Studio LightSwitch

@paul van bladel - Thanks. At this point I am just putting out articles as I learn something :)

By Michael Washington on   12/29/2012 5:38 AM
Gravatar

Re: Using Promises In Visual Studio LightSwitch

Good article (as always), but an unfortunate choice to mix promise objects with promised orders.

By dan houck on   4/5/2014 11:05 AM
Gravatar

Re: Using Promises In Visual Studio LightSwitch

In LS2013 I have not the web folder, I created one and created the promise inside, but it does'nt works.
Sorry for my englist, ain't my native language!

By Haden Yasser on   5/4/2014 11:50 AM
Gravatar

Re: Using Promises In Visual Studio LightSwitch

@Haden Yasser - You can download the code that goes with this article and open it in Visual Studio 2013 and it should work. You can then compare the code to your own.

By Michael Washington on   5/4/2014 11:52 AM

Your name:
Gravatar Preview
Your email:
(Optional) Email used only to show Gravatar.
Your website:
Title:
Comment:
Security Code
CAPTCHA image
Enter the code shown above in the box below
Add Comment   Cancel 
Microsoft Visual Studio is a registered trademark of Microsoft Corporation / LightSwitch is a registered trademark of Microsoft Corporation