Quantcast
Viewing latest article 2
Browse Latest Browse All 7

Computed Fields in the HTML5 client

Introduction

The motivation of LS has always been to make typical LOB patterns easy to implement without limiting the more advanced functionalities.

With the introduction of the HTML Client however, some comforts when developing LS Silverlight applications have disappeared. Many of you feel like JavaScript is holding you back. JavaScript is a powerful language, but definitely requires some studying when you’re accustomed to a strongly typed class-based OOP language like C# or VB.NET.

So let’s start with learning how to implement computed fields in the HTML Client.

Computed Properties in the HTML Client

Currently, there are 2 ways to do this:
- By using a RIAService
- By using the contentItem databinding

Implementing computed properties by extending your entity with a RIA Service is well described in this post by Michael Washington. It is great when having a more complex computation or when you’ll also want to sort or query on the property. However, it also adds some complexity to your code and has a negative impact on maintainability.

Computed properties by using the contentItem databinding is a great option when you’re not afraid of some JavaScripting. So let’s found out a good pattern, in a Object-Oriented way!

Create a simple application with a entity Customer. A customer has a First Name and a Last Name and … a computed full name.
At the Server-side and the SL Client, you can use a shared function for this.

public partial class Customer
{
  partial void FullName_Compute(ref string result)
  {
    result = String.Format("{0} {1}",FirstName,LastName);
  }
}

At the HTML Client however, you can’t add a computed field by using the designer. So let’s do some JavaScripting! (add your own emotion ;))

Open up the Customer.js file and add the following function to the Customer’s prototype.

myapp.Customer.prototype.getFullName = function () {
  /// <summary>Computes the full name of the person.</summary>
  /// <returns type="String">The full name.</returns>
  if (this.FirstName && this.LastName) {
    return this.FirstName + " " + this.LastName;
  }
  return "";
};

By doing this, you’ve added a ‘public’ function to the Customer objects (instantiated after or before this line!). If you’re not familiar with JavaScript, MDN offers some nice documentation, including a introduction to Object-Oriented JavaScript. If you frown when you hear OOP and JavaScript in the same sentence, you’ve got some reading to do Image may be NSFW.
Clik here to view.
:)

Note that we’ve also added some Intellisense documentation. Every time we are using a Customer object, we can now see some documentation about our added computed fields if we reference this js file.

Now add a Browse screen and a Add/Edit screen for your Customers.
At the browse screen, use the postrender event of the Customer rowtemplate to replace the summary text shown:

/// <reference path="../GeneratedArtifacts/viewModel.js" />
/// <reference path="Customer.js" />
myapp.BrowseCustomers.RowTemplate_postRender = function (element, contentItem) {
  function updateCustomerRow() {
    /// <var type="myapp.Customer"></var>
    var customer = contentItem.value;
    $(element).text(customer.getFullName());
  }
  contentItem.dataBind("value.FirstName", updateCustomerRow);
  contentItem.dataBind("value.LastName", updateCustomerRow);
};

Note that the Intellisense for JavaScript doesn’t provide an accurate list of identifiers for the contentItem object.
Image may be NSFW.
Clik here to view.
Intellisense

However you can help Intellisense by declaring the variable as a Customer object. By doing this and referencing the added functions to the Customer prototype, you should now see your computed property function:
Image may be NSFW.
Clik here to view.
Intellisense2

This was easy, up to the Add/Edit screen. Drag the Customer data item to the first rows layout and change the added control to a summary control. Change the display name to Full Name and data bind analogously as with the RowTemplate in the Browse screen.
Image may be NSFW.
Clik here to view.
AddEditCustomer

Some improvements

This pattern is a basic building block and can easily be improved.

  • It would make sense to override the Customer toString function with a custom summary property. However, at first sight the entity’s summary property doesn’t make use of the toString function.
  • You can DRY the dependency data binding by implementing a function like this on the Customer prototype:
    myapp.Customer.prototype.bindToFullName = function (contentItem,callbackFn) {
      /// <summary>Bind to the full name</summary>
      /// <param name="contentItem" type="Element">The contentItem element.</param>
      /// <param name="callbackFn" type="function">The function to call back when the data binding is triggered.</param>
      contentItem.dataBind("value.FirstName", callbackFn);
      contentItem.dataBind("value.LastName", callbackFn);
    };
    

    This would be especially useful when you are dealing with a dependency chain!

Conclusion

We now have 2 good solutions for having a computed property. One does not supersede the other, evaluate case by case which solution you’ll use!


Image may be NSFW.
Clik here to view.
Image may be NSFW.
Clik here to view.

Viewing latest article 2
Browse Latest Browse All 7

Trending Articles