Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

An End-To-End Visual Studio LightSwitch 2013 HTML5 Application

0.00/5 (No votes)
23 Aug 2014 1  
A Visual Studio 2013 LightSwitch HTML 5 Application Tutorial

Image 1

Download the project from here:

Live demo:

Note: You can see an article on creating a report for this application at:

In this article, we will create an end-to-end HTML application in Visual Studio LightSwitch. The purpose is to demonstrate how LightSwitch allows you to create professional business applications that would take a developer days to create. With LightSwitch you can create such applications in under an hour.

You can download LightSwitch at: http://www.microsoft.com/visualstudio/en-us/lightswitch. Also, you must have Visual Studio 2013 (or higher) and the Office Developer Tools for Visual Studio 2013 – March 2014 Update (or higher) installed.

The Scenario

In this example, we will be tasked with producing an application that meets the following requirements for a order tracking system:

  • Products
    • Add Products
    • Edit Products
  • Orders
    • Add Orders
    • Edit Orders
      • Add Order Details
      • Edit Order Details
      • Delete Order Details
    • Delete Orders
  • Business Rules
    • Allow the current user to only see their orders
  • Features
    • Display the number of orders for a User
    • Display the number of order details for an order

image

The application allows you to create a list of Products.

image

Products can be edited.

image

Orders can be created.

image

An Order consists of multiple Order Details.

image

An Order Detail consists of a Product, selected from the list of available Products and a quantity.

Creating the Application

image

Open Visual Studio and select File, then New Project.

image

Create a new LightSwitch HTML Application.

image

The application will be created.

image

The application will display in the Solution Explorer.

image

Right-Click on the Data Sources folder in the Server project and select Add Table.

image

Click on the table name to edit it.

Change the table name to Product.

image

Also, add ProductName and ProductPrice fields to the table.

image

Click the strong>Save button to save the table.

image

Create an Order table (with the fields in the image above).

image

Create an OrderDetail table (with the fields in the image above).

Create Relationships

You will always want to make relationships when tables are related. This allows for optimal strong>LightSwitch application construction. When creating queries, having relationships defined allows you to simply type a period (“.”) and traverse from one entity to another. This saves a lot of coding work and reduces coding errors.

When creating user interfaces, defining relationships allows you to save a lot of coding work because LightSwitch will be able to automatically associate, for example, Order Details with their associated Order.

image

Click on the Relationship button to create a relationship between the Order Detail and the Product table.

image

A box will appear. Select Product for the To table and click OK (ensure the other fields match the image above).

image

You will see that a relationship has been created. you can double-click on the line to edit the relationship.

image

Click on the Relationship button again and make a relationship to the Order table.

Create a Filter

One feature we are required to implement is to only show a user their own orders (and allow an administrator to see all orders). We must keep in mind that all LightSwitch applications expose all data via OData so we must always set security in the server-side code not only in the client-side code (such as the HTML or Silverlight LightSwitch clients).

image

The first thing we need to do is turn on security.

image

Next, we open the Orders table and select Write Code, then Orders_Filter.

Use the following code for the method:

partial void Orders_Filter(ref Expression<Func<Order, bool>> filter)
{
    // Only show the Orders for the current user
    filter = (x => x.UserName == this.Application.User.Name);
}

All data that accesses this table will pass through this filter.

Set Defaults

Keeping in mind that we must set everything that relates to security in server-side code, we realize that marking orders with the UserName of the current user must be set using server-side code so that the UserName cannot be set improperly.

image

Open the strong Orders table and select Write Code, then Orders_Inserting. Use the following code for the method:

 partial void Orders_Inserting(Order entity)
{
    // Set the Username
    entity.UserName = this.Application.User.Name;
}

Do the same for the Orders_Updating event.

Later, we will also set the UserName using client-side code, however, the server side code will always run and overwrite any value set client-side.

Create a Query

Another feature we are required to implement is to show the number of orders for the current user. We will make a query that we can later consume from the client-side.

image

Right-click on the Orders table and select Add Query.

image

Name the query OrdersForUser by clicking on the title and editing it. Save it first, then select the OrdersForUser PreprocessQuery.

Use the following code for the method:

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

Create the User Interface For Products

image

We will first create a screen that will allow us to see Products.

Right-click on the Client node in the Solution Explorer and select Add Screen.

image

Create a Common Screen Set using the Products table.

image

The screens will be created.

image

Hit F5 to run the application.

Note: You will be automatically logged in as TestUser when debugging.

image

Click the Add button to add a Product.

image

Add a product and click the Save button to save it.

image

The Product will show in a list.

Click on the Product to display it in the view detail screen.

image

Click the Edit button to edit the record.

Click the web browser back button to return to the previous page.

Create the Main Page

image

We will now create the Main screen.

Right-click on the Screens folder and select Add Screen…

image

Create a new screen called Main using the Orders table for Screen Data.

image

The first thing we want to do is open a new screen when the user clicks on a Order in the list.

Click on the Tile List control, and select the Item Tap action in the Properties for the control.

image

When the Edit ItemTap Action dialog opens, connect the screen to a new Edit screen.

Select Choose an existing method.

Select Orders.editSelected.

For Navigate To, select (New Screen…) and click OK.

image

The Add New Screen box will show. Select the Order Details and Order OrderDetails and click OK.

image

On the Main page, we need to add a button to create a new Order.

Open the Command Bar on the Main page and click the add button to create a link to the AddEditOrder page (in the Add mode).

image

Right-click on the Main screen and select Set as Home Screen, so that it will be the first screen that comes up when we run the application.

Looking At The Application So Far…

image

Run the application.

image

We see that we can navigate to the Products page using the dropdown.

image

When we click the Add Order button to open the Add Edit Order dialog, the User Name is not filled in for us (also it should be read only).

The Order Date should also be set to the current date as its default value.

image

When we switch to the Order Details tab, we do not have a button to add an Order Detail.

Close the web browser and return to Visual Studio.

Create the Order Detail Edit Screen

image

To allow us to create and edit a Order Detail record, open the AddEditOrder screen and under Order Details (Tab), select Add under the Command Bar.

Select the addAndEditNew method of the OrderDetails collection and (New Screen) for Navigate To.

image

When the Add New Screen dialog shows, select OrderDetail Details as Additional Data to Include.

image

When the AddEditOrderDetail screen opens, right-click on the Rows Layout that contains the Order dropdown and delete it.

We don’t need to show the Order (and allow it to be changed) because it will be set by the time the user gets to this screen.

image

We will create a button to allow the user to edit a Order Detail.

Return to the AddEditOrder screen.

Click on the OrderDetails Tile List, and in the Properties, select the Item Tap event.

In the Edit ItemTap Action dialog, select OrderDetails.editSelected and Navigate To: Add Edit Order Detail (the screen you created in the previous step).

image

When we run the application, we now have a button to Add Order Detail.

image

We can click on the plus in a circle icon in the Product box to see a list so we can select a Product.

image

However, when we create a Order Detail, we see that the display can be improved.

Close the web browser and return to Visual Studio.

Formatting Order Details

image

We return to the Add Edit Order screen and change the Order Details Tile List control to a List.

image

Next, we change the Rows Layout control under the List control to a Custom Control.

image

In the Properties for the Custom Control, we select Edit Render Code.

We use the following code:

myapp.AddEditOrder.rows_render = function (element, contentItem) {
    // We need to wait until the Products for the Order Detail are loaded
    // so we create a binding to "value.Product.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.Product.ProductName", function (newValue) {
        // clear the element
        element.innerHTML = "";
        // Create a template
        var itemTemplate = $("<div><div>");
        // Get the Product name and quantity
        var ProductName = contentItem.value.Product.ProductName;
        var ProductQuantity = "";
        if (contentItem.value.Quantity !== undefined) {
            ProductQuantity = ' [' + contentItem.value.Quantity + ']';
        }
        // Create the final display
        var FinalName = $("<h2>").text(ProductName + ProductQuantity);
        // Complete the template
        FinalName.appendTo($(itemTemplate));
        itemTemplate.appendTo($(element));
    });
};

(Note: This codes uses Promises, for more information about Promises see: Using Promises In Visual Studio LightSwitch. Also see: Writing JavaScript That Implements The Binding Pattern In Visual Studio LightSwitch)

image

When we run the application, the output is formatted as we desire.

Setting Default Values

image

If we run the application, and click the Add Order button…

image

…and try to create an Order it won't save.

We are missing the User Name. We have already added code to overwrite the User Name with the current user, but since we made it a required field, it must still be supplied. We could just make the User Name field a text box and allow the user to type it in, but we can use ServerApplicationContext to insert it client side automatically.

See the following article for a step by step tutorial: Retrieving The Current User In The LightSwitch HTML Client

Using Server Application Context

We will now create a file handler that will use the Server Application Context API to retrieve the currently logged in user’s User Name. We will then call that handler from JavaScript code on the client-side, to fill in the value on the screen.

image

Right-click on the Server project and select Add then New Folder.

Create a folder named Web.

image

Right-click on the Web folder and select Add then New Item.

image

Create a new Generic Handler named GetUserName.ashx.

(Note: You must create the file from scratch so that the proper references are added to the project. If you simply copy and paste, or drag and drop the file into the project, it will not work.)

Use the following code for the file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace LightSwitchApplication.Web
{
    public class GetUserName : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            using (var serverContext = ServerApplicationContext.CreateContext())
            {
                context.Response.ContentType = "text/plain";
                context.Response.Write(serverContext.Application.User.Name);
            }
        }
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

image

Open the Order table, select the HTML Client (tab), Write Code, and then the created method.

Use the following code for the method:

myapp.Order.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);
        })
    });
}

(Note: See Using Promises In Visual Studio LightSwitch for more information on using the msls.promiseOperation.)

image

Lastly, we open the AddEditOrder screen and change the User Name control from a Text Box to a Text label.

image

When we run the application, the User Name and Date are now set when a new record is created.

You will now be able to create and save records.

Calling a Custom Query

Next, we will call the query we created earlier so that we can display the number of Orders for the current user.

image

Open the Main screen, select Add Data Item, and create an Integer property.

image

Drag and drop the property from the View Model to the screen layout.

image

In the Properties, make the label Left-aligned.

image

To set the value for the property, select Write Code, then the created method.

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 a count of the Orders.

Calling a Custom JavaScript Query

image

Now, we desire to show the number of associated Order Details when displaying an Order on the main page.

First, we open the Main page and delete the User Name and Created By fields in the Tile List.

image

Add the Id field to the list.

image

Change the control to a Custom Control.

Use the following code for the Render method of the control:

myapp.Main.Id_render = function (element, contentItem) {
    // Get the current OrderId
    var OrderId = contentItem.value;
    var Int32 = ':Int32';
    // Get all the OrderDetails associated with the current Order
    var filter = '(Order/Id eq ' + msls._toODataString(OrderId, Int32) + ')';
    msls.showProgress(myapp.activeDataWorkspace.ApplicationData.OrderDetails
    .filter(filter)
    .execute()
    .then(function (result) {
        // Loop through each record in the result
        var index = 0;
        var Entities = result.results;
        Entities.forEach(function (entity) {
            // Count the Order Details
            index = index + 1;
        })
        // Set the final output
        var NumberOfOrderDetails = $('<label class=msls-label-text> 
                                   Number of Order Details: ' + index + '</label>');
        NumberOfOrderDetails.appendTo($(element));
    }))
};

image

When we run the application, we see the number of Order Detail records for the Order.

However, we now notice that the totals on the Main page do not show the correct amounts until the page is refreshed. We can automatically refresh the page…

Automatically Refreshing the Page By Using A Custom Button

image

We can create a custom button by selecting the Item Tap event for the Tile List on the Main Page and selecting Write my own method.

image

The method will show up in the View Model on the left side of the screen designer.

Right-click on it and select Edit Execute Code.

Use the following code for the method:

myapp.Main.Orders_ItemTap_execute = function (screen) {
    myapp.showAddEditOrder(null, {
        beforeShown: function (addEditOrderScreen) {
            // Set the Order on the AddEditOrder screen
            // to the selected Order on the Main screen
            addEditOrderScreen.Order = screen.Orders.selectedItem;
        },
        afterClosed: function (addEditScreen, navigationAction) {
            // If the user commits the change,
            // update the selected order on the Main screen
            if (navigationAction === msls.NavigateBackAction.commit) {
                // *****************************************
                // Refresh the Orders
                screen.Orders.load();
            }
        }
    });
};

image

After editing a record, the totals are automatically updated.

Deleting Records

image

Open the Add Edit Order Detail screen and add a button to the Command Bar.

Make a Delete method for the button.

image

Right-click on the Delete method in the View Model and select Edit Execute Code.

Use the following code for the method:

myapp.AddEditOrderDetail.Delete_execute = function (screen) {
    screen.OrderDetail.deleteEntity();
    return myapp.commitChanges().then(null, function fail(e) {
        myapp.cancelChanges();
        throw e;
    });
};

image

When editing an Order Detail, the Delete button will now show.

image

You will have to click the Save button on the Add Edit Order page to commit the change.

We can also add a Delete button to the Add Edit Order screen using the following code:

myapp.AddEditOrder.Delete_execute = function (screen) {
    screen.Order.deleteEntity();
    myapp.commitChanges().then(null, function fail(e) {
        msls.showMessageBox(e.message, {
            title: "Error",
            buttons: msls.MessageBoxButtons.ok
        }).then(function (result) {
            if (result === msls.MessageBoxResult.ok) {
                // Discard Changes
                screen.details.dataWorkspace.ApplicationData
                    .details.discardChanges();
            }
        });
    });
};

image

You will notice that if we try to delete an Order that still has Order Detail records…

image

…it will throw an error because the relationship that we created between the tables earlier was set to not allow an Order to be deleted if there were associated records.

Delete all the Order Details first and then, you can delete the Order.

LightSwitch Help Website Articles

LightSwitch Team HTML and JavaScript Articles

History

  • 24th August, 2014: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here