A LightSwitch application at its core is built by adding data to screens and creating a tree of content items to display and interact with this data. LightSwitch provides a JavaScript API over these content items so that you can interact with them programmatically.
What is a Content Item?
If you open a screen designer in LightSwitch, you will see the data members list on the left and the content item tree to the right:
Content items in the content item tree are bound to data in the data members list. To find out what each content item is bound to, you can select it, and view the Data Binding or Data Context property in the Properties sheet. Note that this cannot be set directly. You bind items by dragging them from the data members list onto the content item tree. Then the correct binding is automatically set:
How to Use a Content Item Programmatically
There are two main ways to get access to a content item programmatically. The first is off of the screen object. The method findContentItem takes in the Name of the content item. This can be used in the screen created entry point or in a custom method to find a specific content item to interact with.
For example:
myapp.AddEditCustomer.created = function (screen) { var contentItem = screen.findContentItem("Details"); }; myapp.AddEditCustomer.MyMethod_execute = function (screen) { var contentItem = screen.findContentItem("Details"); };
The second way is in the render method of a custom control content item or the postRender method of a content item rendered by LightSwitch. In these cases, the content item is passed directly to the function:
myapp.AddEditCustomer.Name_postRender = function (element, contentItem) { }; myapp.AddEditCustomer.Details_render = function (element, contentItem) { };
Content Item API
Once you have a reference to a content item in code, you can call several properties and methods on it. Here are some useful properties:
Name | Type | Settable? | Description |
bindingPath | String | no | Gets the binding path that produces the “value” property |
children | Array | no | Gets the children of the content item. These are child nodes of the item in the screen content tree. |
data | object | no | Gets the source data object |
description | String | yes | Gets or sets the description for this content item. |
displayName | String | yes | Gets or sets the display name for this content item. |
isEnabled | Boolean | yes | Gets a value indicating if the control for this content item should be enabled. |
isReadOnly | Boolean | no | Gets a value indicating if the control for this content item should be read only. |
isVisible | Boolean | yes | Gets or sets a value indicating if the control for this content item should be visible. |
kind | String | no | Gets the kind (from msls.ContentItemKind) of this content item. |
name | String | no | Gets the name of this content item. |
screen | screen | no | Gets the screen that produced this content item. |
stringValue | String | yes | Gets or sets the string representation of the “value” property. |
validationResults | Array | yes | Gets or sets the current set of validation results for this content item. |
value | object | yes | Gets or sets the value that this content item represents. |
Here is the most useful method on a content item:
Name | Description |
dataBind(String bindingPath, callback) | Binds to a source identified by a binding path. |
The dataBind method is used to execute a callback function whenever the property at the end of the bindingPath changes. This is useful because it can keep the UI updated in response to changes to the data. For example, if you have a customer on a View Details screen and want to keep the title of the screen in sync with the name of the customer you can use:
myapp.ViewCustomer.Details_postRender = function (element, contentItem) { contentItem.dataBind("screen.Customer.Name", function (value) { contentItem.screen.details.displayName = value; }); };
If you are curious about the other properties and methods on a content item, Intellisense in the editor greatly helps in discoverability. Intellisense will also help you understand the type of object returned for the “data” and “value” properties.
The interaction between the data and value properties can best be understood with a couple of examples, illustrated in the table below:
Content Item | Data | Binding Path | Value |
Text box displaying “name” property of Customer entity. | Customer entity | “data.Name” | String |
A list of Customers | BrowseCustomers screen | “screen.Customers” | VisualCollection |
In all, there are eight kinds of content items:
ContentItemType | Description | Example Controls | Value of ‘value’ property |
Collection | Represents a query on the screen or a collection property. | List, tile list, table | VisualCollection |
Command | A method either added as part of the command bar or anywhere on the screen. | Button | Screen object |
Details | Represents either an item in a collection, a singular entity on the screen, or a navigation property. | Details picker, rows layout, columns layout, table row, summary property | Entity instance |
Group | A group of content items. | Rows layout, columns layout | Screen object usually but the built-in content item groups of Tabs and Popups have value undefined |
Popup | A popup on the screen. | Rows layout, columns layout | Screen object |
Screen | The screen itself. | Undefined | |
Tab | A tab on the screen. | Rows layout, columns layout | Screen object |
Value | A property of an entity that is not a relationship. | Text, date picker, money viewer, etc. | JS data type: Boolean, String, Number, Date |
Example
Now that you understand what content items are and a little bit about how to use them, let’s try an example that will add additional functionality to an app. When a user of our app goes to add an entity, we want the user to be able to get additional information about a field so he or she best knows how to fill it out. We will do this by using the description property of the content item.
Create a new LightSwitch HTML Client app, and add an intrinsic Customer entity with the following fields:
Create a browse screen for the entity and add a new command bar button to the screen to addAndEditNew Customer.
On the newly created AddEditCustomer screen, select the two content items Name and Age and fill out their descriptions in the property sheet:
This is a pretty trivial description but you can imagine a use case where some explanation might be necessary. Next we will add code to show these descriptions to the user upon request. Add a popup called “Help” to display the description to the user. Add a Data Item to the screen, a local property of type String called “HelpText” that is not required:
Drag this new local property into the popup. Set its control type to be a paragraph and set its label position to none. Your screen content item tree should look like the following:
Next select the “columns” content item and edit the postRender method:
myapp.AddEditCustomer.columns_postRender = function (element, contentItem) { // Look for content items with type either 'details' (a navigation property) // or 'value' (non-relationship properties) var contentItemTypes = []; contentItemTypes.push(msls.ContentItemKind.details); contentItemTypes.push(msls.ContentItemKind.value); // Find these content items starting from the children of the 'columns' content item var matchingContentItems = findMatchingContentItems(contentItemTypes, contentItem); // Find all LABEL elements that are descendants of the parent element rendering the // 'columns' content item var $matchingElements = $(element).find("label"); $.each($matchingElements, function (index) { // Set the LABEL element to float left $(this).css("float", "left"); // Create a new A element that will display the '?' link var $help = $("?"); $help.css({ "cursor": "pointer", "display": "block", "float": "right" }); var correspondingContentItem = matchingContentItems[index]; // Add a click event handler to display the content item description $help.on('click', function (e) { e.preventDefault(); contentItem.screen.HelpText = correspondingContentItem.description; contentItem.screen.showPopup('Help'); }); // Insert the help element as a sibling after the LABEL element $(this).after($help); }); };
This postRender method selects all of the content items specific to editing the properties of a Customer. It then selects the HTML label elements that are displayed on the page, as this is what the user will see when editing the customer. Each label element sequentially corresponds to one of the selected content items. A question mark link is added next to each label with an on-click handler that displays a popup with the corresponding content item’s description. The jQuery library is used for easy DOM manipulation.
Finally we add the helper method used by the postRender method above, findMatchingContentItems. This method takes in contentItemTypes, an array of ContentItemKinds, and parentContentItem, a content item from which to search. It recursively searches all of the children of parentContentItem and returns an array of content items that have a type equal to one of the specified ContentItemKinds.
function findMatchingContentItems(arrayOfTypes, parentContentItem) { var matches = []; // Return an empty array if no children to look at if (parentContentItem.children.length == 0) { return matches; } $.each(parentContentItem.children, function (i, contentItem) { $.each(arrayOfTypes, function (j, type) { if (contentItem.kind == type) { matches.push(contentItem); } }); // Check the child's children for matches matches = matches.concat(findMatchingContentItems(arrayOfTypes, contentItem)); }); return matches; }
Now F5 the app, and click the add button to display the AddEdit dialog:
As we can see each field now has a clickable question mark near it. Clicking the question mark opens the popup with the description of the content item:
Knowing how to interact with content items on the screen is key to creating a LightSwitch application that provides custom experiences for the end user. You can learn more about other aspects of the API with the LightSwitch HTML Client APIs tour or the use of promises in LightSwitch.
- Kevin Mehlhaff, Software Development Engineer in Test, LightSwitch Team