SharePoint TechFest Reference Application Build 2

In part one of this series a simple solution was designed to expose data from a SQL database. However, one of the great things about LightSwitch HTML Client is the ability to extend solutions using jQuery and client side code. In this post, the solution will have some simply customizations made to the UI using jQuery. The solution will also have some simple branding applied using jQuery Mobile’s theme roller. Finally, the solution will be integrated with Bing Maps to display a map of the store.

The solution has three screens:

  • Browse Cities
  • Browse Stores in City
  • View Store

Simple Custom Control

Before we add any additional screens, the way the list of stores is being presented needs to be changed. It currently defaults to the summary view which returns the name of the store. It might be better to include the name of the store and a nicely formatted address.

With the BrowseCitiesInStore screen open, change from the summary view to a custom control.

LightSwitch will add all of the properties of the parent entity. These can be discarded since the focus is on the top level store. All of the properties of the top level entity will be available for our code (yes, we get to finally write some code!).

After removing all of the individual controls below the custom control, click on Edit Render Code in the properties panel to access the code editor. This will create the code stub where the render code needs to be applied.

The code editor creates the new code stub and passes along the element and contentItem.

The element is the DOM object created by the control. The contentItem is the view model containing the data to be bound. There is an excellent post on the LightSwitch Team Blog explaining data binding in the HTML Client, so I will not repeat that content here.

Add the following code after the ”// Write code here.”:

contentItem.dataBind("value", function (item) {        
$("<h2>" + item.StoreName + "</h2>" +
	  "<div>" + item.Address + "<br/>" +
	  item.City + ", " + item.State + " " + item.ZipCode +
	  "</div>").appendTo($(element));
});

This code is jQuery and following the data binding pattern explained in the previously mentioned blog post. Inside the dataBind function, a new set of HTML elements is created using the view model component (in this case, a store). The newly created elements are then appended to the DOM element using the jQuery appendTo function. This should be pretty straightforward if you are familiar with jQuery.

Running the project at this point will display a nicely formatted list of stores which includes the address.

Adding Additional Custom JavaScript Files and Simple Branding

Now is a good time to change the branding of the site. Since jQuery Mobile is used heavily in the solution, the theme roller is a great place to start.

One of my favorite features is the integration with Adobe Kuler swatches. I just randomly picked on of the themes and started dragging colors to the control surfaces. I also set the global options of the theme including the corner radii and fonts.

Download the theme and extract it. When prompted for a theme name, name it anything desired.

Back in the LightSwitch project, go to the Solution Explorer and change from the Logical View to the File View.

In the file view, there are two folders. One is the HTML Client and the other is the Server. To apply branding, open the HTML Client node and then drill into the Content folder. This is where the CSS files will need to be added. Right click on the content folder, hover over Add and select Existing Item.

Browse for the CSS file located under the themes folder. Add the CSS file by clicking on it and then clicking Add.

The file should now appear in the solution. (Using the same process, the custom JavaScript will be added to the Scripts folder under the HTML Client).

With the new CSS file added and the scripts added. Now it is time to open the default.htm file in the HTML Client node. This is just a standard HTML file that has a small number of DIV tags and some script references.

The first thing to change is the stylesheet reference. Simply change from the light-theme.css to the custom CSS uploaded in the project.

Then, at the bottom of the list of script references, add these two lines:

<script type="text/javascript" charset="utf­8" src="https://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&s=1"></script>
<script type="text/javascript" src="Scripts/artis-lightswitch-bing-maps.js"></script>

This adds the script reference for the Bing Maps AJAX control and a custom JavaScript file with code to interact with the Bing Maps API (included in the resources at the end of this post). Save the file and it is time to add an advanced custom control.

The final step is to add an images folder to the HTML Client node and upload an image to use for the map pin. Just simply create a new folder and then add an image to the folder that can be used as a pin.

Advanced Custom Control

Another screen will be added to display a map in a dialog. This screen will be called ViewStoreMap and will show as a dialog. Creating screens is detailed in part 1 of this series. It may be necessary to return to the Logical view of the project in the solution explorer.

Once the screen is created, all of the controls need to be removed to hold the custom control. Starting at the highest level in the hierarchy, delete the node.

The next task is to add a custom control. This is done by making sure the Rows Layout is active and then clicking on Add and choosing New Custom Control at the bottom of the node.

LightSwitch will request a binding path. Provide the binding path to the store.

The custom control will be created and the entity that will be used is the Store for the screen.

Before editing the render code, a few properties need to be set so the Bing Map control knows how large to render the map. In the properties panel of the custom control node, set the Height and Width properties to be a fixed size at 350 pixels.

Also, the screen needs to be flagged as a dialog. This is done in the properties panel for the screen node. Simply adding a check to the Show As Dialog property will take care of setting up the dialog.

Now it is time to add the render code for the map. This is done by clicking on the custom control and choosing Edit Render Code from the property panel. The following code should be added to the code editor after the ‘// Write Code Here’ commented line.

contentItem.dataBind("value", function (newItem) {
	mapDiv = $("<div id=\"MapContainer\"></div>").appendTo($(element));
 
	var store = contentItem.value;
	$(mapDiv).artisBingMapsControl();
	$(mapDiv).artisBingMapsControl("getGeoCodeLocation", store.Address + " " + store.City + ", " + store.State + " " + store.ZipCode,
			function (result) { centerAndShowProperty(mapDiv, result, store); },
			function (XMLHttpRequest, textStatus, errorText) { });
});

Still in the code editor, go to a new line at the end of the file to add the centerAndShowProperty function.

function centerAndShowProperty(mapDiv, result, store) {
    var lattitude = result[0];
    var longitude = result[1];
    $(mapDiv).artisBingMapsControl("centerMap", lattitude, longitude, 14)
             .artisBingMapsControl("addPushPinImageAsync", lattitude, longitude, "images/BoardPin.png", null);
}

In this function, there is a reference to my image (images/BoardPin.png). This should be the name of the file that was added to the solution earlier.

The code file should look similar to the following screenshot:

The final step is to add a new button to show the dialog on the BrowseStoresByCity screen. Open this screen and add a new command to the command bar. Click to add a new button and set the method to the existing method for viewing the selected item.

Click OK and the button may need to be renamed. Just simply rename it to View Map in the properties panel.

One of the nice things about using LightSwitch is the inclusion of several icons for the command buttons. Select an appropriate icon and the UI will reflect that at runtime. Search is selected to provide a magnifying glass.

Now when the application is run, the branding has been applied and a new button shows up on the command bar.

Clicking on the button shows a map using the Bing Maps API.

Resources

And here is the full source for the Bing Maps JavaScript file.

/// <reference path="jquery-1.7.1.js" />
/// <reference path="jquery.mobile-1.1.1.js" />
/// <reference path="msls-1.0.0.js" />

(function ($) {
    var _credentialsKey = "<<Insert Your Bing Maps Key>>";
    Microsoft.Maps.loadModule('Microsoft.Maps.Directions');

    $.widget("msls.artisBingMapsControl",
    {
        options: {
            mapType: Microsoft.Maps.MapTypeId.road,
            zoom: 9,
            showDashboard: false,
            showMapTypeSelector: false,
            tileBuffer: 4,
            useInertia: true
        },

        _create: function () {
        },

        _init: function () {
            this.createMap();
        },

        _destroy: function () {
        },

        getGeoCodeLocation: function (address, success_callback, failed_callback) {
            var geoCodeUrl = "https://dev.virtualearth.net/REST/v1/Locations/" + address + "?key=" + _credentialsKey;

            $.ajax({
                url: geoCodeUrl,
                dataType: "jsonp",
                async: true,
                jsonp: "jsonp",
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    failed_callback(textStatus, errorThrown);
                },
                success: function (result) {
                    var coordinates = null;

                    if (result && result.resourceSets && (result.resourceSets.length > 0) &&
                        result.resourceSets[0].resources && (result.resourceSets[0].resources.length > 0)) {

                        coordinates = result.resourceSets[0].resources[0].point.coordinates;
                        success_callback(coordinates);
                    }
                }
            });
        },

        createMap: function () {
            this.htmlMapElement = this.element[0];
            this.map = new Microsoft.Maps.Map(this.htmlMapElement,
                {
                    credentials: _credentialsKey,
                    mapTypeId: this.options.mapType,
                    showDashboard: this.options.showDashboard,
                    showMapTypeSelector: this.options.showMapTypeSelector,
                    tileBuffer: this.options.tileBuffer,
                    useInertia: this.options.useInertia
                });
        },

        centerMap: function (lat, long, zoom) {
            var loc = new Microsoft.Maps.Location(lat, long);
            this.map.setView({ center: loc, zoom: zoom });
        },

        addPushPinImageAsync: function (lat, lng, image, callback) {
            var location = new Microsoft.Maps.Location(lat, lng);
            var pin = new Microsoft.Maps.Pushpin(location,
                                                 {
                                                     icon: image
                                                 });
            if (callback != null) {
                Microsoft.Maps.Events.addHandler(pin, 'click', callback);
            }
            this.map.entities.push(pin);
        },

        adjustBoundary: function () {
            var locations = new Array();
            for (var i = 0; i < this.map.entities.getLength() ; i++) {
                var l = this.map.entities.get(i);
                if (l.toString() == '[Pushpin]') {
                    locations.push(l.getLocation());
                }
            }

            var rect = Microsoft.Maps.LocationRect.fromLocations(locations);
            this.map.setView({ bounds: rect });
        },

        destroyMap: function () {
        }
    });
}(jQuery));
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s