May
27
Written by:
Michael Washington
5/27/2013 11:12 AM
Visual Studio LightSwitch team member Huy Nguyen is a good person to follow on the Visual Studio LightSwitch forums. He typically provides well explained answers to difficult questions and usually provides code samples, and in some cases downloadable projects.
Previously, I created examples using techniques I learned from some of my favorite posts that he made. That article is called: Visual Studio LightSwitch Screen Navigation and Advanced JavaScript Examples.
In this article, I have created more examples from his latest articles.
Prevent JQuery Mobile From Overriding Custom Controls
In this post, Huy demonstrates how to use the data-role="none" attribute to prevent the underlying JQuery Mobile framework from automatically augmenting and styling certain controls. This can be useful when the JQuery Mobile augmentation causes problems. You can read more about it at this link.
For this example, we create a page called JQueryAndNonJQuery.
We place two Custom Controls on the page, one for Text Boxes and one for Buttons.
In the Properties for each control, we click the Edit Render Code link.
We use the following code for each control:
myapp.JQueryAndNonJQuery.TextBoxes_render = function (element, contentItem) {
var $element = $(element);
var $textbox1 = $('<input type="text" value="Normal Text Box" data-role="none"/>');
var $textbox2 = $('<input type="text" value="JQuery Text Box"/>');
$element.append($textbox1);
$element.append($textbox2);
};
myapp.JQueryAndNonJQuery.Buttons_render = function (element, contentItem) {
var $element = $(element);
var $button1 = $('<input type="button" value="Normal Button" data-role="none"/>');
var $button2 = $('<input type="button" value="JQuery Button" />');
$element.append($button1);
$element.append($button2);
};
When we run the project, we get the following output:
After Editing -- Return Focus and Browser Position to the Item
In this post, Huy shows how we can easily return a user to the last position in a list after navigating away to edit an item in that list.
To implement this, we must create a custom method to open the edit screen (rather than using the normal built-in method when we use the LightSwitch navigation wizard).
We click on the List and select the Item Tap in the Properties for the List.
We select Write my own method, and enter EditPatient for the method name.
The method will show in the View Model on the screen designer.
We right-click on it and select Edit Execute Code.
We use the following code for the method:
myapp.BrowsePatients.EditPatient_execute = function (screen) {
// Set the scrollTopPosition
var scrollTopPosition = $(window).scrollTop();
// Open the Edit Screen
myapp.showAddEditPatient(screen.Patients.selectedItem, {
afterClosed: function () {
// After the Edit screen is closed
// scroll to the saved scrollTopPosition
$(window).scrollTop(scrollTopPosition);
}
});
};
When we run the application, we can scroll to a position in the list and click on an item to edit it.
The edit screen will display.
We can edit the item and save or close the edit screen.
When we return to the list, the list will scroll to the last position (rather than the default behavior of scrolling to the top of the list).
LightSwitch Client Side JavaScript Queries
This post by Huy is about creating Visual Studio LightSwitch client-side JavaScript queries. However, in it, he recommends that the poster use a wizard-like approach to resolve the issue being discussed. In this example, we will implement the solution that Huy suggests (Note: he has a link to his own sample at this link but it does not use a client-side JavaScript query).
When we run the application, we can click the Add New Patient button to add a new record.
We will be able to enter a Name and an Age and click the Validate button.
If a duplicate Name and Age are found, a validation message appears. We will have the option to navigate back.
The key thing to note in this example, is that the values are validated against the entire database using a client-side query that runs server-side. If we had a large amount of records in the database, the query would still run fast because it does not require the records to be transferred client-side to be searched.
We can change the information and click the Validate button again.
When the values pass validation, the Save button appears.
We can click the Save button to save the record.
The record will be saved, and it will display in the list.
Creating The Example
The first step is to create a AddNewPatient screen.
We create two Tabs and hide the second Tab.
We set the screen to hide the Tab Titles, and set the screen type to Browse (so the default Save button will not show).
We use the Add Data Item button to add a Patient entity.
This entity will be used to hold the final record we are constructing with the wizard.
We also create two string properties, PatientName and PatientAge.
We drag and drop the PatientName and PatientAge to the first Tab.
We also create a Validate button for the first Tab and use the following code for the method:
myapp.AddNewPatient.Validate_execute = function (screen) {
// get the values entered
var PatientName = screen.PatientName;
var PatientAge = screen.PatientAge;
// Always show step 2 at this point
screen.showTab("Step2");
screen.details.displayName = "Step 2";
// Clear ValidationMessage
screen.ValidationMessage = "";
if (PatientName == null || PatientAge == null) {
screen.ValidationMessage = "Both values are required -- Click Back and try again";
// Hide the Save button
var SaveButton = screen.findContentItem("Save");
SaveButton.isVisible = false;
// Stop processing
return;
}
// Check to see if this is a duplicate -- construct a query
var filter = "(PatientName eq " + msls._toODataString(PatientName, ":String") +
") and (PatientAge eq " + msls._toODataString(PatientAge, ":Int32") + ")";
// Query the database
myapp.activeDataWorkspace.ApplicationData
.Patients
.filter(filter)
.execute()
.then(function (result) {
// Get the results of the query
var currentPatient = result.results[0];
// If there are any results show duplicate record error
if (currentPatient != null && currentPatient != 'undefined') {
screen.ValidationMessage = "Duplicate Found -- Click Back and try again";
// Hide the Save button
var SaveButton = screen.findContentItem("Save");
SaveButton.isVisible = false;
} else {
// There is no duplication
screen.ValidationMessage = "Validation passed -- Save to continue";
// Show the Save button
var SaveButton = screen.findContentItem("Save");
SaveButton.isVisible = true;
}
}, function (error) {
alert(error);
});
};
The Save button is on the second Tab.
We use the following code for the method called by the button:
myapp.AddNewPatient.Save_execute = function (screen) {
// Get the values entered
var PatientName = screen.PatientName;
var PatientAge = screen.PatientAge;
// Set the values for the entity
screen.Patient.PatientName = PatientName;
screen.Patient.PatientAge = PatientAge;
// Save and close
myapp.commitChanges();
};
We open the BrowsePatients screen and create a button called Add New Patient.
We use the following code for the method called by the button:
myapp.BrowsePatients.AddNewPatient_execute = function (screen) {
// Open the AddNewPatient Screen
myapp.showAddNewPatient({
beforeShown: function (addEditPatientScreen) {
// Create new Patient here so that
// discard will work.
var newPatient = new myapp.Patient;
addEditPatientScreen.Patient = newPatient;
},
afterClosed: function (AddNewPatientScreen, navigationAction) {
// Refresh Patients
screen.Patients.load();
}
});
};
Client-Side JavaScript API
The API methods for the client-side JavaScript queries can be found in the vsdoc.js file:
Note: For more information on the OData commands to use in the “filter” expression, see: Filter System Query Option ($filter)
filter: function filter(expression) {
/// <summary>
/// Filters results using an expression defined
/// by the OData $filter system query option.
/// </summary>
/// <param name="expression" type="String">
/// An OData filter expression.
/// </param>
/// <returns type="msls.DataServiceQuery" />
},
orderBy: function orderBy(propertyName) {
/// <summary>
/// Orders results by a property in ascending order.
/// </summary>
/// <param name="propertyName" type="String">
/// A property name.
/// </param>
/// <returns type="msls.DataServiceQuery" />
},
orderByDescending: function orderByDescending(propertyName) {
/// <summary>
/// Orders results by a property in descending order.
/// </summary>
/// <param name="propertyName" type="String">
/// A property name.
/// </param>
/// <returns type="msls.DataServiceQuery" />
},
thenBy: function thenBy(propertyName) {
/// <summary>
/// Further orders results by a property in ascending order.
/// </summary>
/// <param name="propertyName" type="String">
/// A property name.
/// </param>
/// <returns type="msls.DataServiceQuery" />
},
thenByDescending: function thenByDescending(propertyName) {
/// <summary>
/// Further orders results by a property in descending order.
/// </summary>
/// <param name="propertyName" type="String">
/// A property name.
/// </param>
/// <returns type="msls.DataServiceQuery" />
var q = new _DataServiceQuery(this);
},
expand: function expand(expression) {
/// <summary>
/// Expands results by including additional navigation properties using
/// an expression defined by the OData $expand system query option.
/// </summary>
/// <param name="expression" type="String">
/// An OData expand expression (a comma-separated
/// list of names of navigation properties).
/// </param>
/// <returns type="msls.DataServiceQuery" />
},
skip: function skip(count) {
/// <summary>
/// Bypasses a specified number of results.
/// </summary>
/// <param name="count" type="Number">
/// The number of results to skip.
/// </param>
/// <returns type="msls.DataServiceQuery" />
},
top: function top(count) {
/// <summary>
/// Restricts results by a specified number.
/// </summary>
/// <param name="count" type="Number">
/// The number of results to return.
/// </param>
/// <returns type="msls.DataServiceQuery" />
},
includeTotalCount: function includeTotalCount() {
/// <summary>
/// Requests that the total result count as if the skip and top
/// operators were not applied is returned in addition to the results.
/// </summary>
/// <returns type="msls.DataServiceQuery" />
}
Special Thanks
A very special thanks to LightSwitch Team member Huy Nguyen.
Download Code
The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx
(you must have Visual Studio 2012 Update 2 installed to run the code)