Hits

Dec 22, 2011

ASP.Net MVC4 Mobile Tutorial - Part 3

Summary

Continuing from our discussion around a sample ASP.Net MVC4 Mobile application, this final post will discuss the final piece; the UI and how it all comes together.


You can download the full sample from here.


Update: I forgot to include the SQL scripts for the database, as pointed out by @Anonymous. So download this script, create a new database and run it. Do not forget to update your SQL connection string in the MVC application!

The User Interface

The default project uses the jQuery mobile plugin to target mobile devices. The jQuery mobile plugin is touch-optimized for smartphones and tablets and it targets iOS, Android, Blackberry, Bada, Windows Phone, Palm WebOS, Symbian and MeeGo.

Lets start with the JavaScript logic, which will perform the interaction between the HTML UI and the JSON web service.

  • In the Scripts folder, add a folder called com then sukul underneath that and finally babyfeeding underneath that
  • In the final babyfeeding folder, add a JavaScript file and called it proxy.js
  • Copy and paste the following code into the js file
  • if (Sukul == undefined) var Sukul;
    if (!Sukul) Sukul = {};
    
    //Constructor
    Sukul.Proxy = function (siteBaseUrl) {
        // constructor
        Sukul.Proxy.prototype.baseUrl = siteBaseUrl;
        Sukul.Proxy.prototype.heartBeatUrl = siteBaseUrl + "/Services/BabyMonitorService.svc/HeartBeat";
        Sukul.Proxy.prototype.FeeedingUrl = siteBaseUrl + "/Services/BabyMonitorService.svc/AddFeedingEntry"
        Sukul.Proxy.prototype.DiaperingUrl = siteBaseUrl + "/Services/BabyMonitorService.svc/AddDiaperingEntry"
    }
    
    Sukul.Proxy.prototype = {
        CallWebService: function (url, input, successCallBack, errorCallBack) {
            //Uncomment the next line to support JSONP
            //url = url + "?callback=?";       
            $.ajax({
                async: false,
                cache: false,
                type: "GET",
                contentType: "application/json; charset=utf-8",
                url: url,
                dataType: "json",
                data: input,
                success: successCallBack,
                error: errorCallBack
            });
    
        },
    
        HeartBeat: function (successFunction, failFunction) {
            this.CallWebService(this.heartBeatUrl, "", successFunction, failFunction);
        },
        AddFeeding: function (UserId, FeedType, FeedAmount, successFunction, failFunction) {
            var input = "UserId=" + UserId + "&FeedType=" + FeedType + "&FeedAmount=" + FeedAmount;
            this.CallWebService(this.FeeedingUrl, input, successFunction, failFunction);
        },
        AddDiapering: function (UserId, DiaperType, successFunction, failFunction) {
            var input = "UserId=" + UserId + "&DiaperType=" + DiaperType;
            this.CallWebService(this.DiaperingUrl, input, successFunction, failFunction);
        }
    };
  • The JavaScript is structured using objects and namespaces. Every JavaScript object contains an inner class called Prototype. By defining methods on this inner class, we can encapsulate object variables and methods and share them across concrete instances of the class. In the code above, the Proxy object defines the following methods:
    • CallWebService - helper method for invoking the JSON service
    • HearBeat - invokes the Heat method call for diagnostics
    • AddFeeding - creates a feed entry by taking input from the form and invoking the web service
    • AddDiapering - creates an entry for a diaper change by taking input from the form and invoking the web service
  • Finally, we encapsulate the Proxy object inside the Sukul object to create a namespace so that the proxy object can be referenced like so: Sukul.Proxy

The Index.cshtml View

Copy and paste the following code for the Index page

@{
    ViewBag.Title = "Baby Log Home";
}

<script type="text/javascript">
    $(document).ready(function () {
        $("#btnSubmit").click(function () {

            $("#txtLastEntry").val("Last: ");

            // Create the proxt class
            var proxy = new Sukul.Proxy("@Request.Url.GetLeftPart(UriPartial.Authority)");
            // Add the feeding entry
            if ($("#chkFeed").attr("checked") != undefined && $("#chkFeed").attr("checked") == "checked") {
                proxy.AddFeeding("@Membership.GetUser().UserName", $("#drpType").val(), $("#drpAmount").val(),
                    function (result) {
                        // succeeded
                        $("#txtLastEntry").val($("#txtLastEntry").val() + $("#drpAmount option:selected").text() +
                        " of " + $("#drpType option:selected").text());
                    },
                    function (jqXHR, textStatus, errorThrown) {
                        // failed
                        var err = "Details: " + textStatus;
                        if (errorThrown != undefined) {
                            err += "\rMore details : " + errorThrown;
                        }
                        alert(err);
                    });
            }
            // Add the diapering entry
            if ($("#chkDiaper").attr("checked") != undefined && $("#chkDiaper").attr("checked") == "checked") {
                proxy.AddDiapering("@Membership.GetUser().UserName", $("#drpDiaper").val(),
                    function (result) {
                        // succeeded
                        $("#txtLastEntry").val($("#txtLastEntry").val() + ", " + 
                        $("#drpDiaper option:selected").text() + " diaper");
                    },
                    function (jqXHR, textStatus, errorThrown) {
                        // failed
                        var err = "Details: " + textStatus;
                        if (errorThrown != undefined) {
                            err += "\rMore details : " + errorThrown;
                        }
                        alert(err);
                    });
            }
        });
    });
</script>
<div data-role="fieldcontain" data-inset="true">
    <fieldset data-role="controlgroup">
        <legend>Feed Details</legend>
        <input id='chkFeed' name='chkFeed-1' type="checkbox" checked="checked" class="custom" />
        <label for="chkFeed">
            Log Feed</label>
    </fieldset>
    <fieldset data-role="controlgroup">
        <legend>Feed Type:</legend>
        @Html.DropDownList("drpType", new List<SelectListItem> { 
            new SelectListItem { Text="Bottle", Value="Bottle", Selected=true }, 
            new SelectListItem { Text="Left", Value="Left" }, 
            new SelectListItem { Text="Right", Value="Right" }, 
        })
    </fieldset>
    <fieldset data-role="controlgroup">
        <legend>Amount:</legend>
        @Html.DropDownList("drpAmount", new List<SelectListItem> { 
            new SelectListItem { Text="0.5 oz.", Value="0_5" }, 
            new SelectListItem { Text="1.0 oz.", Value="1_0" }, 
            new SelectListItem { Text="1.5 oz.", Value="1_5" }, 
            new SelectListItem { Text="2.0 oz.", Value="2_0" }, 
            new SelectListItem { Text="2.5 oz.", Value="2_5", Selected=true }, 
            new SelectListItem { Text="3.0 oz.", Value="3_0" }, 
            new SelectListItem { Text="3.5 oz.", Value="3_5" }, 
            new SelectListItem { Text="4.0 oz.", Value="4_0" }, 
            new SelectListItem { Text="4.5 oz.", Value="4_5" }, 
            new SelectListItem { Text="5.0 oz.", Value="5_0" }, 
            new SelectListItem { Text="5.5 oz.", Value="5_5" }, 
            new SelectListItem { Text="6.0 oz.", Value="6_0" }, 
            new SelectListItem { Text="6.5 oz.", Value="6_5" }, 
            new SelectListItem { Text="7.0 oz.", Value="7_0" }, 
            new SelectListItem { Text="7.5 oz.", Value="7_5" }, 
            new SelectListItem { Text="8.0 oz.", Value="8_0" }, 
            new SelectListItem { Text="8.5 oz.", Value="8_5" }, 
            new SelectListItem { Text="9.0 oz.", Value="9_0" } 
        })
    </fieldset>
</div>
<div data-role="fieldcontain" data-inset="true">
    <fieldset data-role="controlgroup">
        <legend>Diaper Details</legend>
        <input id='chkDiaper' name='chkDiaper-1' type="checkbox" class="custom" />
        <label for="chkDiaper">
            Log Diaper</label>
    </fieldset>
    <fieldset data-role="controlgroup">
        <legend>Diaper:</legend>
        @Html.DropDownList("drpDiaper", new List<SelectListItem> {
            new SelectListItem { Text="Wet", Value="wet", Selected=true },
            new SelectListItem { Text="Dirty", Value="dirty" },
            new SelectListItem { Text="Both", Value="both" }
        })
    </fieldset>
</div>
<div data-role="fieldcontain" data-inset="true">
    <input id="btnSubmit" type="submit" value="Submit" data-role="button" />
    <fieldset data-role="controlgroup">
        <input id="txtLastEntry" readonly="readonly" type="text" />
    </fieldset>
</div>

The HTML code builds the input form for entering the feed and diaper change details and the Javascript code collects the input, creates the proxy class and calls its methods to invoke the web service.

Notice how the @ tag is used to inject runtime variables, such as the logged on user and the base url.

Home Page view 1
Home Page view 2
Keywords: ASP.Net MVC Mobile jQuery Azure

2 comments:

  1. I am working through your tutorial.
    Using download.
    Application run failed with:

    Message=The connection name 'LocalSqlServer' was not found in the applications configuration or the connection string is empty.

    I suspect something to do with the database setup.

    Upgraded all js packages, ran again, same error.

    Detailed Exception:

    System.Configuration.ConfigurationErrorsException was unhandled by user code
    Message=The connection name 'LocalSqlServer' was not found in the applications configuration or the connection string is empty. (C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config line 238)
    Source=System.Web
    BareMessage=The connection name 'LocalSqlServer' was not found in the applications configuration or the connection string is empty.
    Filename=C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine.config
    Line=238
    StackTrace:
    at System.Web.Configuration.ProvidersHelper.InstantiateProvider(ProviderSettings providerSettings, Type providerType)
    at System.Web.Configuration.ProvidersHelper.InstantiateProviders(ProviderSettingsCollection configProviders, ProviderCollection providers, Type providerType)
    at System.Web.Security.Membership.InitializeSettings(Boolean initializeGeneralSettings, RuntimeConfig appConfig, MembershipSection settings)
    at System.Web.Security.Membership.Initialize()
    at System.Web.Security.Membership.get_Provider()
    at System.Web.Security.Membership.ValidateUser(String username, String password)
    at JSLearning.Controllers.AccountController.LogOn(LogOnModel model, String returnUrl) in C:\Users\Peter\Downloads\JSLearning.Mobile\JSLearning\Controllers\AccountController.cs:line 42
    at lambda_method(Closure , ControllerBase , Object[] )
    at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
    at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
    at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
    at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.b__12()
    at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
    InnerException: System.Configuration.Provider.ProviderException
    Message=The connection name 'LocalSqlServer' was not found in the applications configuration or the connection string is empty.
    Source=System.Web
    StackTrace:
    at System.Web.Util.SecUtility.GetConnectionString(NameValueCollection config)
    at System.Web.Security.SqlMembershipProvider.Initialize(String name, NameValueCollection config)
    at System.Web.Configuration.ProvidersHelper.InstantiateProvider(ProviderSettings providerSettings, Type providerType)
    InnerException:

    ReplyDelete
    Replies
    1. Thanks for the catch. Post updated.

      Delete

I always welcome feedback from my readers.