Tuesday, June 30, 2015

Bucket List Demo (JavaScript and .Net examples using RESTful API and JSON)

Here are some examples I put together that I really enjoy, because of their simplicity.

The HTML example demonstrates the following:

- MySafeInfo's WICK API (RESTful)
- JavaScript
- jQuery (2.1.4)
- Bootstrap (3.3.5)
- Font Awesome (4.3.0)
- AJAX (asynchronous and synchronous)

 <!DOCTYPE html>  
   
 <html xmlns="http://www.w3.org/1999/xhtml">  
   <head>  
     <title>Bucket List</title>  
   
     <style type="text/css">  
       body {  
         margin: 0px 25px !important;  
       }  
   
       td.icons {  
         font-size: 18px !important;  
       }  
   
       td.icons i {  
         cursor: pointer;  
         padding: 0 15px;  
       }  
   
       .icon-cancel.disabled {  
         color: #cccccc;  
         cursor: not-allowed;  
       }  
     </style>  
   
     <!-- jquery -->  
     <script src="//code.jquery.com/jquery-2.1.4.min.js"></script>  
   
     <!-- bootstrap -->  
     <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">  
     <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>  
       
     <!-- font awesome -->  
     <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />  
   
     <!-- custom script -->  
     <script type="text/javascript">  
       // variables  
       var readerKey = "28SFkEKyZucdjEvaqYGLD3SY2d9dsnqb";  
       var insertKey = "3InDNvlJnYzSGAHRjT2tUEB4MRygJtuV";  
       var updateKey = "iP3wwSUtuSLFoi4HNzmZIOazxckoldaN";  
       var deleteKey = "LqNQuiJ5Eg8FSzWBJZj2FLO0n0PDrM7L";  
       var table = "BucketList"  
   
       // format  
       String.prototype.format = function () {  
         var args = arguments;  
         return this.replace(/{(\d+)}/g, function (match, number) {  
           return typeof args[number] != 'undefined'  
            ? args[number]  
            : match  
           ;  
         });  
       };  
   
       $(function () {  
         // initialize  
         BindData();  
   
         // bind data  
         function BindData() {  
           // variables  
           var grid = $("#grid");  
   
           // ajax variables  
           var type = "GET";  
           var url = "https://mysafeinfo.com/wick/{0}/tables/{1}".format(readerKey, table);  
           var contentType = "application/json; charset=utf-8";  
           var dataType = "json";  
           var data = "";  
           var async = true;  
   
           // get the data from database table  
           $.ajax({  
             type: type,  
             url: url,  
             contentType: contentType,  
             dataType: dataType,  
             data: data,  
             async: async  
           }).done(function (result) {  
             // variables  
             var result = $(result);  
             var rows = "";  
             var columns = "";  
   
             // heading  
             $("h3.table-results").text("{0} record{1}".format(result.length, (result.length > 1 | result.length == 0) ? "s" : ""));  
   
             // get the template (schema) for this table  
             var template = GetTableTemplate();  
   
             // append a blank record so they can do an inline add in the grid  
             result.splice(0, 0, template);  
   
             // for each row  
             result.each(function (i, item) {  
               // variables  
               var key = "ID";  
               var id = item[key];  
   
               // clear columns  
               columns = "";  
   
               // begin new row  
               rows = "{0}<tr data-id='{1}'>".format(rows, id);  
   
               // get column list  
               for (var column in item) {  
                 // variables  
                 var value = item[column];  
   
                 // get column headers  
                 columns = "{0}<th>{1}</th>".format(columns, column);  
   
                 // check to see if this is an existing record or the blank record for the inline add  
                 // if an existing record show the data as-is  
                 // if the blank record show NEW for the ID column and empty textboxes for the other fields  
                 if (id > 0) {  
                   rows = "{0}<td data-column='{2}' data-value='{1}'>{1}</td>".format(rows, value, column);  
                 }  
                 else {  
                   if (column == key) {  
                     rows = "{0}<td data-column='{2}' data-value='0'><i class='fa fa-plus-circle icon-new' alt='New' title='New'></i></td>".format(rows, value, column);  
                   }  
                   else {  
                     rows = "{0}<td data-column='{2}' data-value='{1}'><input type='text' value='' maxlength='100' data-column='{2}'/></td>".format(rows, value, column);  
                   }  
                 }  
               }  
   
               // check to see if this is an existing record or the blank record for the inline add  
               // if an existing record show the edit and delete icons  
               // if the blank record show the save and cancel icons  
               if (id > 0) {  
                 rows = "{0}<td class='icons text-right'><i class='fa fa-pencil icon-edit' alt='Edit' title='Edit'></i><i class='fa fa-trash-o icon-delete' alt='Delete' title='Delete'></i><i class='fa fa-save icon-save hidden' title='Save' alt='Save'></i><i class='fa fa-times icon-cancel hidden' title='Cancel' alt='Cancel'></i></td></tr>".format(rows);  
               }  
               else {  
                 rows = "{0}<td class='icons text-right'><i class='fa fa-plus icon-save' title='Save' alt='Save'></i><i class='fa fa-times icon-cancel disabled' title='Cancel' alt='Cancel'></i></td></tr>".format(rows);  
               }  
             });  
   
             // columns  
             columns = "{0}<th></th>".format(columns);  
   
             // table  
             var table = "<table id='table-data' class='table table-striped table-responsive table-hover results'><thead><tr>{0}</tr></thead><tbody>{1}</tbody></table>".format(columns, rows);  
   
             // add data to grid  
             grid.html(table);  
           }).always(function () {  
               
           });  
         }  
   
         // edit  
         $("body").delegate("table.results tbody tr td i.icon-edit", "click", function () {  
           // variables  
           var td = $(this).parent("td");  
           var tr = $(td).parent("tr");  
   
           // toggle icons  
           $(td).children("i.icon-edit").addClass("hidden");  
           $(td).children("i.icon-delete").addClass("hidden");  
           $(td).children("i.icon-save").removeClass("hidden");  
           $(td).children("i.icon-cancel").removeClass("hidden");  
   
           // add input fields to each cell  
           for (var i = 1; i < tr.children("td").length - 1; i++) {  
             // variables  
             var cell = tr.children("td")[i];  
   
             // add input to cell  
             $(cell).html("<input type='text' value='{1}' maxlength='100' data-column='{0}'/>".format($(cell).data("column"), $(cell).text().trim()));  
   
             // set focus to the first input  
             if (i == 1) { $(cell).children("input").focus(); }  
           };  
   
           // keydown event to capture enter key  
           $(window).keydown(function (event) {  
             if (event.which == 13) {  
               event.preventDefault();  
               td.children("i.icon-save").trigger("click");  
             }  
           });  
         });  
   
         // delete  
         $("body").delegate("table.results tbody tr td i.icon-delete", "click", function () {  
           if (confirm("Are you sure you want to delete this record?")) {  
             // variables  
             var tr = $(this).parent("td").parent("tr");  
             var id = $(tr).children("td").first().text();  
   
             // ajax variables  
             var type = "DELETE";  
             var url = "https://mysafeinfo.com/wick/{0}/tables/{1}/{2}".format(deleteKey, table, id);  
             var contentType = "application/json; charset=utf-8";  
             var dataType = "json";  
             var data = "";  
             var async = false;  
   
             // delete  
             $.ajax({  
               type: type,  
               url: url,  
               contentType: contentType,  
               dataType: dataType,  
               data: data,  
               async: async  
             }).done(function (result) {  
               // bind data  
               BindData();  
   
               // show message  
               alert(result.Message);  
             }).always(function () {  
                 
             });  
           }  
         });  
   
         // save  
         $("body").delegate("table.results tbody tr td i.icon-save", "click", function () {  
           // variables  
           var tr = $(this).parent("td").parent("tr")  
           var id = tr.data("id");  
           var request = "";  
           var isValid = false;  
   
           // create request  
           for (var i = 1; i < tr.children("td:not(.icons)").length; i++) {  
             // controls  
             var input = $(tr.children("td")[i]).children("input");  
   
             // variables  
             var column = $(input).data("column");  
             var value = $(input).val().trim();  
   
             // append to request  
             request = '{0} "{1}":"{2}",'.format(request, column, value)  
   
             // is valid flag if at least one field has data  
             if (value.length > 0) {  
               isValid = true;  
             }  
           }  
   
           // make sure at least one field has data, otherwise nothing to add/update  
           if (!isValid) {  
             alert("Please enter a value for at least one field.");  
             tr.children("td").find("input").first().focus();  
             tr.children("td").find("input").first().select();  
             return;  
           }  
   
           // format json request  
           request = "{{0}}".format(request.substring(1, request.length - 1));  
   
           // check to see if we need to do an insert or an update  
           if (id > 0) {  
             // ajax variables  
             var type = "PUT";  
             var url = "https://mysafeinfo.com/wick/{0}/tables/{1}/{2}".format(updateKey, table, id);  
             var contentType = "application/json; charset=utf-8";  
             var dataType = "json";  
             var data = request;  
             var async = false;  
   
             // update  
             $.ajax({  
               type: type,  
               url: url,  
               contentType: contentType,  
               dataType: dataType,  
               data: data,  
               async: async  
             }).done(function (result) {  
               // bind  
               BindData();  
   
               // message  
               alert(result.Message);  
             }).always(function () {  
               // remove key event listener  
               RemoveListener();  
             });  
           }  
           else {  
             // ajax variables  
             var type = "POST";  
             var url = "https://mysafeinfo.com/wick/{0}/tables/{1}".format(insertKey, table);  
             var contentType = "application/json; charset=utf-8";  
             var dataType = "json";  
             var data = request;  
             var async = false;  
   
             // insert  
             $.ajax({  
               type: type,  
               url: url,  
               contentType: contentType,  
               dataType: dataType,  
               data: data,  
               async: async  
             }).done(function (result) {  
               // bind  
               BindData();  
   
               // message  
               alert(result.Message);  
             }).always(function () {  
               // remove key event listener  
               RemoveListener();  
             });  
           }  
         });  
   
         // cancel  
         $("body").delegate("table.results tbody tr td i.icon-cancel", "click", function () {  
           // variables  
           var tr = $(this).parent("td").parent("tr")  
           var id = tr.data("id");  
   
           // short-circuit if this is a new record  
           if (id < 1) {  
             return;  
           }  
   
           // set defaults  
           for (var i = 1; i < tr.children("td:not(.icons)").length; i++) {  
             var td = $(tr.children("td")[i]);  
             td.text(td.data("value"));  
           }  
   
           // toggle icons  
           $(this).parent("td").children("i.icon-edit").removeClass("hidden");  
           $(this).parent("td").children("i.icon-delete").removeClass("hidden");  
           $(this).parent("td").children("i.icon-save").addClass("hidden");  
           $(this).parent("td").children("i.icon-cancel").addClass("hidden");  
   
           // remove key event listener  
           RemoveListener();  
         });  
   
         function GetTableTemplate() {  
           // variables  
           var template;  
   
           // ajax variables  
           var type = "GET";  
           var url = "https://mysafeinfo.com/wick/{0}/tables/{1}/template".format(readerKey, table);  
           var contentType = "application/json; charset=utf-8";  
           var dataType = "json";  
           var data = "";  
           var async = false;  
   
           // get table template  
           $.ajax({  
             type: type,  
             url: url,  
             contentType: contentType,  
             dataType: dataType,  
             data: data,  
             async: async  
           }).done(function (result) {  
             template = result;  
           }).always(function () {  
   
           });  
   
           // return  
           return template;  
         }  
   
         function RemoveListener() {  
           $(window).unbind("keydown");  
         }  
       });  
     </script>  
   </head>  
   
   <body>  
     <!-- container for header to indicate how many records were retrieved -->  
     <h3 class="table-results">0 records</h3>  
   
     <!-- container for html table built dynamically from our ajax call -->  
     <div class="table-responsive">  
       <div id="grid"></div>  
     </div>  
   </body>  
 </html>  

I've also included examples using .Net 4.5 (C# and VB.Net) for those looking to call a RESTful API from the server-side, which can be helpful when working with key-based APIs, so you can hide your API keys. The .Net 4.5 examples demonstrate the following:

- MySafeInfo's WICK API (RESTful)
- Json.NET (Newtonsoft.Json)
- WebClient.UploadString

 using System;  
 using System.Net;  
 using Newtonsoft.Json;  
                            
 public class Program  
 {  
      public static void Main()  
      {  
           // variables  
           string Table = "BucketList";  
           string InsertKey = "3InDNvlJnYzSGAHRjT2tUEB4MRygJtuV";  
           string DeleteKey = "LqNQuiJ5Eg8FSzWBJZj2FLO0n0PDrM7L";  
           string InsertUrl = string.Format("https://mysafeinfo.com/wick/{0}/tables/{1}", InsertKey, Table);  
           PostResult PostResult = new PostResult();  
           WickResult WickResult = new WickResult();  
           BucketList BucketList = new BucketList { Description = "Run a mini-marathon", Notes = "2016 OneAmerica 500 Festival Mini-Marathon", Date = "May 2016" };  
   
           // use Json.NET (Newtonsoft.Json) to serialize the data object  
           // https://www.nuget.org/packages/Newtonsoft.Json  
           string Data = JsonConvert.SerializeObject(BucketList);  
   
           // post the data to the MySafeInfo WICK API  
           PostResult = SubmitRequest(Url: InsertUrl, Data: Data);  
   
           // use Json.NET (Newtonsoft.Json) to deserialize json result into a strongly typed data object  
           // https://www.nuget.org/packages/Newtonsoft.Json  
           if (PostResult.Success)  
           {  
                WickResult = JsonConvert.DeserializeObject<WickResult>(PostResult.Message);  
           }  
   
           // debug  
           Console.WriteLine(string.Format("WICK Input: {0}", Data));  
           Console.WriteLine(string.Format("WICK Output: {0}", PostResult.Message));  
           Console.WriteLine(string.Format("ID: {0}", WickResult.ID));  
           Console.WriteLine(string.Format("Success: {0}", WickResult.Success));  
           Console.WriteLine(string.Format("Message: {0}", WickResult.Message));  
   
           // just for fun we are going to delete the record to show how simple a delete is  
           if (WickResult.Success)  
           {  
                Console.WriteLine(string.Format("Delete: {0}", SubmitRequest(Url: string.Format("https://mysafeinfo.com/wick/{0}/tables/{1}/{2}", DeleteKey, Table, WickResult.ID), Method: "DELETE").Message));  
           }  
      }  
   
      public static PostResult SubmitRequest(string Url, string Data = "", string Method = "POST", string ContentType = "application/json; charset=utf-8")  
      {  
           // variables  
           PostResult Result = new PostResult();  
   
           try  
           {  
                // web client  
                using (WebClient Client = new WebClient())  
                {  
                     // content type  
                     Client.Headers[HttpRequestHeader.ContentType] = ContentType;  
   
                     // post data and get result  
                     Result.Message = Client.UploadString(address: Url, method: Method, data: Data);  
                     Result.Success = true;  
                }  
           }  
           catch (Exception ex)  
           {  
                Result.Message = ex.Message;  
           }  
   
           // return  
           return Result;  
      }  
   
      // helper classes  
      public class BucketList  
      {  
           public string Description { get; set; }  
           public string Notes { get; set; }  
           public string Date { get; set; }  
      }  
   
      public class PostResult  
      {  
           public bool Success { get; set; }  
           public string Message { get; set; }  
      }  
   
      public class WickResult  
      {  
           public int ID { get; set; }  
           public bool Success { get; set; }  
           public string Message { get; set; }  
      }  
 }  

As you can see, the server side code is relatively simple since we can leverage Json.NET to serialize and deserialize our data, and we can use built in .Net namespaces (WebClient) to perform our RESTful operations against the API.

Here are links to each example:

Bucket List Demo (HTML, JavaScript, jQuery)
Bucket List Demo (.Net 4.5, C#)
Bucket List Demo (.Net 4.5, VB.Net)

Whether you are using client-side scripting or server side scripting, you can see that using JSON data with a RESTful API can be very easy to implement.

Matt Pavey is a Microsoft Certified software developer who specializes in ASP.Net, VB.Net, C#, AJAX, LINQ, XML, XSL, Web Services, SQL, jQuery, and more. Follow on Twitter @matthewpavey

0 comments: