Wednesday, 29 April 2015

AngularJS Custom Validator Example - Comparing Two Dates

Below is an example of AngularJS custom validator to compare an end date with a start date to make sure that the end date is equal or bigger than the start date. To see basic usage of AngularJS validation, please see my previous post.

HTML codes:
<!DOCTYPE html>
<html>

  <head>
    <script src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>
    <script src="https://code.angularjs.org/1.3.15/angular-messages.js"></script>
    <script src="script.js"></script>
  </head>

  <body ng-app="validationExample">
    <div ng-controller="MyCtrl as vm">
      <form name="myForm" novalidate="" ng-submit="vm.submitted(myForm, vm.input)">
        <span class="input-label">Start Date</span> 
        <input type="date" name="startDate" ng-model="vm.input.startDate" required />
        <span ng-messages="myForm.startDate.$error" ng-messages-include="errors-template.html"></span>
        <br />       
        <span class="input-label">End Date</span> 
        
        <input type="date" name="endDate" ng-model="vm.input.endDate" start-date="{{vm.input.startDate.yyyymmdd()}}" compare-with-start-date />
        <span ng-messages="myForm.endDate.$error" ng-messages-include="errors-template.html"></span>
        <br />             
        <button>submit</button>
      </form>
    </div>
    
    <!-- error messages template -->
    <script id="errors-template.html" type="text/ng-template">
        <span ng-message="required">* required!</span>
        <span class="form-error" ng-message="checkEndDate">* end date cannot be earlier than start date</span>
    </script>
  </body>

</html>

JavaScript codes:
var myApp = angular.module('validationExample', ['ngMessages'])

myApp.controller('MyCtrl', [function () {
    var vm = this;
    vm.submitted = function(form, input) {
      if(form.$valid) {
        alert('submitted');
      }
    }
} ]);

myApp.directive("compareWithStartDate", function () {
    return {
        restrict: "A",
        require: "?ngModel",
        link: function (scope, element, attributes, ngModel) {
            validateEndDate = function (endDate, startDate) {
                if (endDate && startDate) {
                    startDate = new Date(startDate);
                    startDate.setHours(0, 0, 0, 0);
                    endDate = new Date(endDate);
                    endDate.setHours(0, 0, 0, 0);
                    return endDate >= startDate;
                }
                else {
                    return true;
                }
            }

            // use $validators.validation_name to do the validation
            ngModel.$validators.checkEndDate = function (modelValue) {
                var startdate = Date.parse(attributes.startDate);
                var enddate = modelValue;
                return validateEndDate(enddate, startdate);
            };
            
            // use $observe if we need to keep an eye for changes on a passed value
            attributes.$observe('startDate', function (value) {
                var startdate = Date.parse(value);
                var enddate = Date.parse(ngModel.$viewValue);
                
                // use $setValidity method to determine the validation result 
                // the first parameter is the validation name, this name is the same in ng-message template as well
                // the second parameter sets the validity (true or false), we can pass a function returning a boolean
                ngModel.$setValidity("checkEndDate", validateEndDate(enddate, startdate));
            });
        }
    };
});


// function to parse date time object into yyyy-mm-dd format string
Date.prototype.yyyymmdd = function () {
    var yyyy = this.getFullYear().toString();
    var mm = (this.getMonth() + 1).toString(); // getMonth() is zero-based         
    var dd = this.getDate().toString();

    return yyyy + '-' + (mm[1] ? mm : "0" + mm[0]) + '-' + (dd[1] ? dd : "0" + dd[0]);
};

See the example in Plunker.

Thursday, 16 April 2015

Form Validation in Ionic or AngularJS

On this post we will see how to do form validation in AngularJS or Ionic framework. At the moment, Ionic framework does not have its own validation features and relies on the underlying framework.

Basic Usage with Built-In Validators
To begin, first we need to make sure that we have a reference to angular.js file. Then we need to do the following steps:
- give a name to our form
- put novalidate="" attribute on the form
So we should have something like this on our form:
<form name="myForm" novalidate="" ng-submit="" >
 . . .
</form>
- add a unique name to each input field
- add validation attributes that we need on the input fields. AngularJS provides some validation directives such as these; required, pattern, minlength, maxlength, min and max. It also has basic built-in validators for these input types; text, number, url, email and date.
An example on an input field:
<input type="text" name="name" ng-model="vm.input.name" required />
- add an error message to be displayed for each validator checking the corresponding property name on input field's $error object in conditional statement like ng-if or ng-show. Properties under $error object with the same names as the validators' names exist for us to use. The properties are on this format; formName.fieldName.$error.builtInValidatorName. For example:
<span ng-show="myForm.name.$error.required == true">* required</span>
- on a method that is called in ng-submit, check whether the form is valid using formName.$valid before doing any action

Below is a complete example:
<!-- HTML page -->
<body ng-app="validationExample">
    <div ng-controller="MyCtrl as vm">
      <form name="myForm" novalidate="" ng-submit="vm.submitted(myForm, vm.input)">
        <div>
          <input type="text" name="name" ng-model="vm.input.name" required>
          <span ng-show="myForm.name.$error.required == true">test: * required</span>
        </div>
        <button>submit</button>
      </form>
    </div>
</body>

// JavaScript codes
var myApp = angular.module('validationExample', [])

myApp.controller('MyCtrl', [function () {
    var vm = this;
    vm.submitted = function(form, input) {
      if(form.$valid) {
        // post the form
        . . .
      }
    }
} ]);
See these codes on Plunker.


Creating Custom Validator
If we would like to create a custom validator, we would need to do these in addition of the above steps:
- create a directive
- on the directive's link function, use the new AngularJS $validators object on ngModel controller to do the validation. We need to create a function property on ngModel.$validators. By doing so, we register the function as a new validation rule. Each time the model changes, the validation rule is invoked. For example:
link: function(scope, element, attributes, ngModel) {
 ngModel.$validators.wrongInitial = function(modelValue) {
   . . .
 };
}
A corresponding property on input field's $error object is also created that can be used for checking validity.
- similar like in using built-in validator, we need to add an error message to be displayed by checking the newly created corresponding property on the input field's $error object:
<span ng-show="myForm.name.$error.wrongInitial == true">* must start with letter r</span>

Additional codes to be added from the first example:
<!-- HTML page -->
<input type="text" name="name" ng-model="vm.input.name" start-with-r />
<span ng-show="myForm.name.$error.wrongInitial == true">* must start with letter r</span>

// JavaScript codes
myApp.directive("startWithR", function() {
    return {
      restrict: "A",
      require: "?ngModel",
      link: function(scope, element, attributes, ngModel) {
        ngModel.$validators.wrongInitial = function(modelValue) {
          if (modelValue) {
            return modelValue.charAt(0).toUpperCase() == 'R';
          }
          else {
            return true;
          }
        };
      }
    };
});
See a complete example on Plunker.


Using ngMessages to Display Error Messages
In the recent version of AngularJS, started with version 1.3, there is a new feature that we could use to display messages including form error messages. To use this, we need to:
- include a reference to angular-messages.js file in our page
- inject ngMessages module to our AngularJS app
var myApp = angular.module('validationExample', ['ngMessages'])
- if there are only a few fields to be validated, we could specify each error message for each field like this:
<!-- use ng-messages with each field's $error object in this format; formName.fieldName.$error -->
<div ng-messages="myForm.name.$error" >  
        <!-- specify an error message for each validator -->
 <span ng-message="required">Name is required!</span>
 <span ng-message="wrongInitial">Name must start with letter r</span>
</div>
- however if we know that we are going to repeat this multiple times, we could use a template instead:
<!-- create a template by using script tag with type="text/ng-template" and give an Id -->
<script id="errors-template.html" type="text/ng-template" >  
        <!-- specify an error message for each validator -->
 <span ng-message="required">* required!</span>
 <span ng-message="wrongInitial">* must start with letter r!</span>
</script>
Then use the template to display error message(s) on each field:
<!-- use ng-messages with each field's $error object and ng-messages-include referring to the template Id -->
<span ng-messages="myForm.name.$error" ng-messages-include="errors-template.html" />
See the complete example on Plunker.


References:
Working with Validators and Messages in AngularJS
Validation in Ionic Framework Apps with ngMessages

Friday, 27 March 2015

How to Pull File from an Android App

The other day when I tested my Apache Cordova based app, I tried to get a file from my Android phone to test that the file was created correctly by the app. I wanted to copy the file to a location somewhere in my Windows based desktop. Below are the steps of how I do this:
- open a command prompt
- enter 'adb shell', you might need to run this inside a folder that has adb.exe if that is not accessible globally
- enter 'run-as    your.application.name'
- enter 'chmod 777    targeted_File_Path' in order to give full access to the file
So after entering these commands, the command prompt would look like this:
C:\Users\Me>adb shell
shell@zara:/ $ run-as your.application.name
run-as your.application.name
shell@zara:/data/data/your.application.name $ chmod 777 /data/data/your.application.name/files/filename.jpg
data/data/your.application.name/files/filename.jpg                   <
shell@zara:/data/data/your.application.name $ 
- quit the adb shell or open a new command prompt window
- enter 'adb pull    targeted_File_Path    destination_Desktop_Folder'
On command prompt, it will be something like:
C:\Users\Me>adb pull /data/data/your.application.name/files/filename.jpg c:/DestinationDirectory
2097 KB/s (19335 bytes in 0.009s)


References:
http://stackoverflow.com/questions/13006315/how-to-access-data-data-folder-in-android-device
http://www.codeproject.com/Articles/825304/Accessing-internal-data-on-Android-device

Thursday, 19 March 2015

Example of Writing Image to File in Apache Cordova

Below is an example of how to writing image to a file in Apache Cordova. To have more understanding of basic file operations, please see my previous post.
window.resolveLocalFileSystemURL(my_Directory_Path,
function (dirEntry) {
 dirEntry.getFile(path_Of_File_To_Be_Written, { create: true }, 
  // getFile() success
  function (fileEntry) {
   fileEntry.createWriter(
    // createWriter() success
    function (fileWriter) {
     fileWriter.onwriteend = function (e) {
      . . .
     };

     fileWriter.onerror = function (e) {
      . . .
     };

     fileWriter.write(dataURIToBlob(getBase64Image(image_To_Be_Written, "image/jpeg")));
     // or if we already have a canvas
     //fileWriter.write(dataURIToBlob(canvas.toDataURL("image/jpeg")));
    }, 
    // createWriter() error
    function (error) {
     . . .
    }
   );
  },
  // getFile() error
  function (error) {
   . . .
  }
 );
});

A function to convert an image's base-64 encoded data to Blob type (this is taken from http://stackoverflow.com/questions/12391628/how-can-i-upload-an-embedded-image-with-javascript):
function dataURIToBlob(dataURI) {
 // serialize the base64/URLEncoded data
 var byteString;
 if (dataURI.split(',')[0].indexOf('base64') >= 0) {
  byteString = atob(dataURI.split(',')[1]);
 }
 else {
  byteString = unescape(dataURI.split(',')[1]);
 }

 // parse the mime type
 var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

 // construct a Blob of the image data
 var array = [];
 for (var i = 0; i < byteString.length; i++) {
  array.push(byteString.charCodeAt(i));
 }
 return new Blob(
  [new Uint8Array(array)],
  { type: mimeString }
 );
}
Also a function to get base-64 encoded data from an image:
// type is either "image/png" or "image/jpeg"
function getBase64Image(img, type) {
    // create an empty canvas element
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

    // copy the image contents to the canvas
    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0);

    // get the base-64 encoded data
    var dataURL = canvas.toDataURL(type);
 // toDataURL() actually has two optional parameters:
 // - type. The default value is 'image/png'.
 // - jpegQuality. A decimal value ranging from 0 to 1 to determine the quality of the data to be generated from a jpeg type image.
 //   The default value is browser dependant.

    return dataURL;
}

Monday, 16 March 2015

Examples of File Operations in Apache Cordova

To be able to do any operation with directory/file in Apache Cordova, we need to access and get hold of the directory/file entry first. Then only after that we will be able to do any directory/file operation. This could be a very different approach from other frameworks that we have used before in dealing with file and file system.


Creating and Writing File
Let start with an example to create and write a file:
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function (dirEntry) {
 console.log("got directory entry", dirEntry);
 dirEntry.getFile("myFilename.txt", { create: true }, 
  // getFile() success
  function (fileEntry) {
   console.log("got file entry", fileEntry);
   fileEntry.createWriter(
    // createWriter() success
    function (fileWriter) {
     fileWriter.onwriteend = function (e) {
      console.log('write is successful');
      . . .
     };

     fileWriter.onerror = function (e) {
      console.log('write is failed', e);
      . . .
     };

     var blob = new Blob(['. . . some text . . .'], { type: 'text/plain' });
     fileWriter.write(blob);
    },
    // createWriter() error
    function (error) {
     . . .
    }
   );
  },
  // getFile() error
  function (error) {
   . . .
  }
 );
});

In the example above, we use resolveLocalFileSystemURL() function to get a directory or file entry from a directory/file system path (i.e. cordova.file.dataDirectory). resolveLocalFileSystemURL() has two parameters:
- the first parameter is a directory or file path
- the second one is the callback function to be executed once it succeed. A directory or file reference entry object is passed to the callback function.

Once we have hold of the file or directory entry object, we can do a number of operations such as creating, writing, reading, copying, moving, renaming or deleting the file. In this case, we want to create a new file and write into it. To do this, we need to call getFile() function first. The function has four parameters:
- the filename or file path
- function options (optional parameter). It has two properties with boolean values, namely; create and exclusive. create: true will create a file if it does not exist. To make the function throws an error if the file exists, set exclusive: true.
- on success callback function, passing a file reference entry object
- on error callback function (optional parameter), an error object is passed to the callback
Then after we get the file entry object, we call createWriter() function that will create a file writer object once successful. Next we call its write() function. The file writer object also has onwriteend() and onerror() callback functions.


Reading File
window.resolveLocalFileSystemURL(myFilePath, function (dirEntry) {
 fileEntry.file(
  // success
  function(file) {
     var reader = new FileReader();

     reader.onloadend = function(e) {
       console.log('file is read');
       . . .
     };

     reader.readAsText(file);
  }, 
  // error
  function (error) {
    . . .
  }
 );
});
In the example, we see that after we get a file reference entry object, we use file() method in order to create a file object of the intended file to be passed to FileReader readAsText() function.


Deleting File
window.resolveLocalFileSystemURL(myFilePath, 
 function (fileEntry) { 
  fileEntry.remove(
   // success
   function () { 
    console.log('file is removed'); 
    . . .
   }, 
   // error
   function (error) {
    . . .
   }
  ); 
 } 
); 
In this last example, we call file entry object's remove() function to delete a file.

Thursday, 5 March 2015

Cropping Image with JavaScript and Canvas

Below is an example of how to crop image using JavaScript and HTML Canvas element.
var canvas = document.createElement('canvas');
canvas.width = 150;
canvas.height = 150;
//var canvas = document.getElementById('myCanvas');  // create a new canvas or use the existing one in document

var context = canvas.getContext('2d');

var sourceImg = new Image();

sourceImg.onload = function () {    // make sure the image is loaded first before cropping it

 context.drawImage(sourceImg, source_starting_x_coord, source_starting_y_coord, 
  width_to_be_cropped_from_source_coord, height_to_be_cropped_from_source_coord, 
  starting_x_coord_on_destination_canvas, starting_y_coord_on_destination_canvas, 
  width_of_cropped_image_to_put_on_canvas, heigth_of_cropped_image_to_put_on_canvas);
 //context.drawImage(sourceImg, 0, 50, 150, 150, 0, 0, 150, 150);

 // display or do anything we like with the result
 //imageDisplay = canvas.toDataURL();

}

sourceImg.src = toBeCroppedImageSource;  // can be an image url or base-64 encoded data

Wednesday, 25 February 2015

Cordova Build Fails with Exit Code 2 and 8

When building or debugging an Android app using Apache Cordova and Visual Studio, if you encounter this kind of error below:
Could not create the Java Virtual Machine. C:\...\MyApp\EXEC 1 1 MyApp 
A fatal exception has occurred. Program will exit. C:\...\MyApp\EXEC 1 1 MyApp 
C:\...\MyApp\bld\Debug\platforms\android\cordova\build.bat: Command failed with exit code 2 C:\...\MyApp\EXEC 1 1 MyApp 
The command ""C:\Users\Me\AppData\Roaming\npm\node_modules\vs-mda\vs-cli" build --platform "Android" --configuration "Debug" --projectDir . --projectName "MyApp" --language "en-US" --buildServerUrl "" --buildTarget "AndroidDevice"" exited with code 8. C:\Users\Me\AppData\Roaming\npm\node_modules\vs-mda-targets\Microsoft.MDA.targets 99 5 MyApp
You can try to kill Android Debug Bridge process using task manager or command prompt. To do the first way, open Windows Task Manager (ctrl + shift + esc), find adb.exe and then right click and select 'End Process Tree'. Otherwise using command prompt, type adb kill-server and adb start server commands. For example, in my environment:
C:\Users\Me\AppData\Local\Android\android-sdk\platform-tools\adb kill-server
C:\Users\Me\AppData\Local\Android\android-sdk\platform-tools\adb start server
After that, try to build or debug again. If it is still not good then restart Visual Studio.

If you would like to try other ways before restarting Visual Studio, you can try these steps as well:
- close the emulator if you are using emulator
- clean the build files in Visual Studio using 'Clean Solution'
- if still there are files under 'My_App_Name\bld\Debug\platforms' folder then delete those manually
- then try to rebuild or start debugging again

Wednesday, 11 February 2015

Handling Exceptions in ASP.NET MVC Application

There are several ways to handle uncaught exceptions in ASP.NET MVC. We could use the default HandleErrorAttribute filter, extend the filter, create our own error filter, override OnException method in controller or use Application_Error method in global.asax.


Using Default MVC Error Handler
By default an MVC project applies HandleErrorAttribute filter globally in global.asax.
public static void RegisterGlobalFilters(GlobalFiltersCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}
It returns the default error view (Error.cshtml) created inside Views\Shared folder.

To have this error handler working, CustomErrors must be set to 'On' in web.config:
<customErrors mode="On">
</customErrors>


Using HandleErrorAttribute Filter in Controller or Action
If we only want to apply the HandleError filter in some controllers or actions, then we need to remove HandleErrorAttribute filter addition in RegisterGlobalFilters method in global.asax. Then apply the filter on specific controllers or actions only.

We can simply use this one:
[HandleError]
This will handle all possible errors it could catch and show the default error view (Error.cshtml) located inside Views\Shared folder.

Otherwise we can specify what type of error to be handled and what view to be displayed. For example:
[HandleError(ExceptionType=typeof(ArgumentException), View="ArgumentError")]
We can also stack these filters to handle different types of error on controllers or actions.

This filter only catches errors originated from inside controller actions and other filters applied to them. It also only handles HTTP 500 Internal Server error. The filter does not do much. After catching errors, it will only show the error page.

Apart from this filter, if we want to catch other than HTTP 500 error, we can set the customErrors in the config file for a particular view to be loaded when the error happens. This is commonly used for HTTP 404 Not Found error:
<customerrors mode="On">
 <error statuscode="404" redirect="~/Error/PageNotFound">
 </error>
</customerrors>


Extending HandleErrorAttribute Filter
By extending this filter, we can add more capabilities such as to log error and handle errors generated from AJAX requests. Below is an example:
public class ExtendedHandleErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        // if exception is handled already
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
        {
            return;
        }

        // pass other HTTP exceptions to global application error handler
        if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
        {
            return;
        }

        if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
        {
            return;
        }

        // if the request is AJAX then return JsonResult else normal view
        if (filterContext.HttpContext.Request["X-Requested-With"] == "XMLHttpRequest" || ((filterContext.HttpContext.Request.Headers != null) && (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")))
        {
            filterContext.Result = new JsonResult
                    {
                        JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                        Data = new
                        {
                            error = true,
                            message = filterContext.Exception.Message
                        }
                    };
        }
        else
        {
            base.OnException(filterContext);
        }

        // log the error
        //. . .

    }
}
In this example, we are just handling HTTP 500 error (Internal Server error) to comply with HTTP standards. Other errors will be passed to global application error handler (Application_Error() method). If you'd like to return a different view, please see that part of codes in the next example (creating custom error filter).


Creating Custom Error Filter
If extending HandleErrorAttribute above is not enough then we can create our own custom error filter. The filter class will inherit from FilterAttribute and IExceptionFilter.
public class CustomHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        // if exception is handled already
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
        {
            return;
        }

        // pass other HTTP exceptions to global application error handler
        if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
        {
            return;
        }

        /*if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
        {
            return;
        }*/

        // if the request is AJAX then return JsonResult else ViewResult
        if (filterContext.HttpContext.Request["X-Requested-With"] == "XMLHttpRequest" || ((filterContext.HttpContext.Request.Headers != null) && (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")))
        {
            filterContext.Result = new JsonResult
                        {
                            JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                            Data = new
                            {
                                error = true,
                                message = filterContext.Exception.Message
                            }
                        };
        }
        else
        {
            // if we want to pass detailed error info to the view
            var controllerName = (string)filterContext.RouteData.Values["controller"];
            var actionName = (string)filterContext.RouteData.Values["action"];
            var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

            filterContext.Result = new ViewResult
            {
                ViewName = "theViewName",
                ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
                TempData = filterContext.Controller.TempData
            };
        }

        // log the error
        //. . .

        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = 500;

        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}
The example codes handle AJAX and normal requests, log error and return a particular view for a normal request.


Overriding OnException Method in Controller
Another way to handle error in ASP.NET MVC application is by overriding OnException method in controller. However, like the HandleErrorAttribute filter above, this method only catches errors that happen inside a controller. Other errors such as data binding or route errors will not be caught. We could also return a view by assigning a ViewResult to its ExceptionContext object's Result property. Below is an example:
protected override void OnException(ExceptionContext context)
{
    // pass other errors to global application error handler
    if (context.Exception is InvalidOperationException)
    {
        // do some error logging
        //. . .

        // if we want to pass detailed error info to the view
        var controllerName = (string)context.RouteData.Values["controller"];
        var actionName = (string)context.RouteData.Values["action"];
        var model = new HandleErrorInfo(context.Exception, controllerName, actionName);

        var result = new ViewResult
                {
                    ViewName = "theViewName",
                    ViewData = new ViewDataDictionary(model),
                    TempData = context.Controller.TempData
                };
        context.Result = result;

        // configure the response object
        context.ExceptionHandled = true;
        context.HttpContext.Response.Clear();
        context.HttpContext.Response.StatusCode = 500;
        context.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}


Using Application Global Error Handler
Lastly, we can also use Application_Error() method in global.asax. This method catches all unhandled errors and is the last resort before the yellow error screen. Many developers only use this method alone to handle all kind of errors in the application. When there is a need to handle errors (or some specific errors) at controller or action method level then the other error handlers mentioned above can be used.

Below is an example of using Application_Error() method and its related error controller and view to catch errors:
global.asax Application_Error() method:
protected void Application_Error(object sender, EventArgs e)
{
    HttpContext httpContext = ((MyApplicationName)sender).Context;
    Exception exception = Server.GetLastError();

    if (httpContext.Request["X-Requested-With"] == "XMLHttpRequest" || ((httpContext.Request.Headers != null) && (httpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")))
    {
        // handle AJAX request

        httpContext.ClearError();
        Response.StatusCode = 500;
        Response.ContentType = "application/json";
        Response.StatusDescription = "my custom status description";    // => Response.StatusDescription maps to jqXHR or XMLHttpRequest.statusText

        // => Response.Write() maps to jqXHR or XMLHttpRequest.responseText  
#if DEBUG
        Response.Write(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
        {
            errorMessage = exception.ToString()
        }));
        //Response.Write(exception.ToString());
#else
        Response.Write("an application error has occurred");
#endif
    }
    else
    {
        // non AJAX request

        IController errorController = new MyWebProject.Controllers.ErrorController();
#if DEBUG
        {
            // get information to be passed to view as model
            string currentController = string.Empty;
            string currentAction = string.Empty;
            RouteData currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
            if (currentRouteData != null)
            {
                if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
                {
                    currentController = currentRouteData.Values["controller"].ToString();
                }

                if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
                {
                    currentAction = currentRouteData.Values["action"].ToString();
                }
            }

            ((Controller)errorController).ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction);
        }
#else
        {
            // only show a message
            ((Controller)errorController).ViewData.Model = "error message . . .";
        }
#endif

        string action = "Error";

        if (exception is HttpException)
        {
            // get the action for different error codes
            switch (((HttpException)exception).GetHttpCode())
            {
                case 404:
                    action = "NotFound";
                    break;

                // other errors
            }
        }

        httpContext.ClearError();
        httpContext.Response.Clear();
        httpContext.Response.StatusCode = exception is HttpException ? ((HttpException)exception).GetHttpCode() : 500;

        // avoid IIS7 getting involved
        httpContext.Response.TrySkipIisCustomErrors = true;

        // execute the error controller
        RouteData routeData = new RouteData();
        routeData.Values["controller"] = "Error";
        routeData.Values["action"] = action;
        //IController errorController = new NSWHealth.ICPBS.Web.Controllers.ErrorController(); // for readability only, this is already done above 
        //((Controller)errorController).ViewData.Model = new HandleErrorInfo(exception, currentController, currentAction); // for readability only, this is already done above
        errorController.Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
    }
}

error controller:
public class ErrorController : Controller
    {
        public ActionResult Error()
        {
            return View();
        }

        public ViewResult NotFound()
        {
            //Response.StatusCode = 404;  //could be set to 200 as well
            return View("NotFound");
        }
    }

error view:
@{
    ViewBag.Title = "Error";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Error</h2>
<div>
    @if (Html.IsDebug())
    {
        <div>
            <p>
                <b>Exception:</b> @Model.Exception.Message<br />
                <b>Controller:</b> @Model.ControllerName<br />
                <b>Action:</b> @Model.ActionName
            </p>
            <div style="overflow:scroll">
                <pre>
                @Model.Exception.StackTrace
                </pre>
            </div>
        </div>
    }
    else
    {
        <div style="min-height:460px">
            An error has occurred: @Model 
        </div>
    }
</div>


References and further reading:
Handling Errors Effectively in ASP.NET MVC
Exception Handling in ASP.NET MVC
Exception Handling in MVC

Friday, 6 February 2015

IsDebuggingEnabled, #if DEBUG, Conditional("DEBUG") and Debugger.IsAttached

HttpContext.IsDebuggingEnabled checks the <compilation debug="..."/> value inside <system.web> node in web.config.
if (HttpContext.Current.IsDebuggingEnabled)
{
    // if debug mode is enabled in web.config
    . . .
}

#if DEBUG or #if RELEASE checks for particular build configuration. Whether a build configuration uses DEBUG or RELEASE, this is defined in the project build properties (right click the project -> Properties -> Build tab).
The drawback with this is if there is a property or method declared outside being renamed (through refactoring) then the property or method called inside one of its if ... else ... conditions might not be renamed as well causing error when the build configuration is switched.
#if DEBUG
. . .
#else
. . .
#endif

The Conditional attribute helps to overcome this issue. An example:
[System.Diagnostics.Conditional("DEBUG")]
public void MyMethod()
{ 
   . . . 
}


System.Diagnostics.Debugger.IsAttached checks whether an active debugger is attached to the system.
if(System.Diagnostics.Debugger.IsAttached)
{
   . . . 
}

Friday, 23 January 2015

How to Check Objects References in Visual Studio

We can use a tool in Visual Studio when debugging to check whether two objects point to the same instance. First, add the objects/variables that we want to check to Watch list. Right click one of the variables, then select Make Object ID.

After doing this, an ID will be displayed on the Value column in this format '{ID_Number#}'. At the same time, all other objects that point to the same instance will have this displayed on their values as well.

If two or more variables have the same ID number then it means that they point to the same instance.

If we rather would like to check the objects manually, we could use Object.ReferenceEquals(object1, object2) method that will return a boolean value.

Tuesday, 13 January 2015

Using JavaScript Prototype for Object Oriented Approach


Prototype property
Every object in JavaScript has a prototype. This prototype can be seen by accessing __proto__ property in recent modern browsers except IE.
var n = 5;
console.log(n.__proto__);

var myObj = {};
console.log(myObj.__proto__);


Function prototype property
There is another similar term that is quite confusing in JavaScript world, it is the prototype property. This is not the real prototype property like the one above. However this is a property that is found in every function in JavaScript. I prefer to call this property; function prototype.
function Person(firstname, lastname) {
    this.firstname = firstname;
    this.lastname = lastname;
    this.fullName = function () {
        return this.firstName + ' ' + this.lastName;
    }
}
console.log(Person.prototype);

// below will yield 'undefined' because it is not a function
var n = 5;
console.log(n.prototype);

// this will be false as a function prototype is not the same as its prototype property
Person.prototype == Person.__proto__;


Creating object with new keyword
When we initialise a new object with new keyword, the object's real prototype will point to the constructor function's function prototype property.
var john = new Person('john', 'king');

// john's prototype will point to Person's function prototype property
console.log(john.__proto__ == Person.prototype)  // true
The new object will have whatever defined inside the constructor function plus access to whatever in its prototype. So if we add more properties to the constructor function's function prototype, these will be accessible by the created objects. This will be explained more in details below.

A very important rule that need to be remembered from here is:
newObject.__proto__ = TheFunction.prototype


Prototypes chain
In JavaScript, when an object property is called, if it is not found within the object, JavaScript will try to traverse up it's prototypes chain to find it. If it already reaches the root but still cannot find the property, undefined will be returned.
var animal = { name: 'animal', eats: true };

var fish = { name: 'fish', swims: true };
// set fish prototype to animal
fish.__proto__ = animal;

var tuna = { name: 'tuna', canBeCanned: true };
// set tuna prototype to fish
tuna.__proto__ = fish;

console.log(tuna.swims);
console.log(tuna.eats);
Below is the structure created (on Firebug):

As we can see tuna's prototype is fish object and fish's prototype is animal object. The text in bold are properties that are available to the containing objects.


Adding a property to a prototype chain
When we have an established prototypes chain then if we added a new property to one of the prototype objects in the chain, this new property would be accessible by the lower objects in the chain.
// based on the example above we add a new property to animal
animal.moves = true;
console.log(tuna.moves) // lower objects in the chain can access it

// we can also add a new property through a prototype link
// this example below add a new property at animal's level because we have set fish.__proto__ = animal
fish.__proto__.breathes = true;
console.log(tuna.breathes)


Using these prototype behaviours for object oriented approach
Having knowledge of prototype behaviours described above, we can implement object oriented concept in our JavaScript codes. We will also need to use function prototype and new keyword to set up relationships as the __proto__ property is not available in some browsers. As an example, we could have something like this:
function Coder() {
    this.name = 'coder';
    this.code = function () {
        return "coding now";
    }
}

function JSCoder() {
    this.name = 'JSCoder';
    this.writeSomeJSCodes = function () {
        return "writing: this.__proto__ = . . .";
    }
}

// set up the relationship
JSCoder.prototype = new Coder();
// this is saying that every newly created JSCoder object will have its prototype property points to a Coder object

var jack = new JSCoder();
// because we have set above JSCoder.prototype = new Coder()
//  and because of the rule: newObject.__proto__ = TheFunction.prototype
//  then this one below is implemented implicitly when jack is created:
//  jack.__proto__ = JSCoder.prototype  which equals to a Coder object ( new Coder() )

console.log(jack.writeSomeJSCodes());
console.log(jack.code());

// we can also add a new property to a function prototype then it will be accessible by existing child object(s)
JSCoder.prototype.debugging = function () { return 'debugging some codes' };
// this is saying that because of the rule: newObject.__proto__ = TheFunction.prototype
//  when a new JSCoder object is created: var jack = new JSCoder()
//  then this will apply: jack.__proto__ = JSCoder.prototype
//  and JSCoder.prototype has been set to a Coder object ( new Coder() )
//  so when a new property is added,
//  JSCoder.prototype is a Coder object plus the new property
//  thus jack's prototype ( jack.__proto__ ) is a Coder object plus the new property

console.log(jack.debugging());

What will happen if we modify the function prototype to point to a new object? Existing objects will not be affected, however new objects created after the modification will have their prototypes point to the new object.
// modify JSCoder function prototype to point to a new object
JSCoder.prototype = { sing: function () { return 'singing' } };
console.log(jack); // existing objects' prototypes do not change

// however new objects' prototypes will point to the new object
var jim = new JSCoder();
console.log(jim);


References and further readings:
A Plain English Guide to JavaScript Prototypes
Understanding “Prototypes” in JavaScript
Understanding JavaScript Prototypes
Prototypal inheritance
OOP in JS, Part 2 : Inheritance

Monday, 5 January 2015

Implementing Asynchronous Tasks with $q in AngularJS

AngularJS has provided $q service that can be used to implement asynchronous tasks. It uses deferred objects and the promises they return to accomplish asynchronous runs.

A basic example of using $q:
function myAsyncFunc() {
  // create a deferred object
  var deferredObject = $q.defer();

  . . .

  // if for a reason, we want to cancel this task
  if (errorOccured) {
        deferredObject.reject('an error has occured');
        return deferredObject.promise;
  }

  // after the job is completed, call resolve()
  deferredObject.resolve();

  . . .

  // return the promise
  return deferredObject.promise;
}

// then on the caller
myAsyncFunc().then(
  // success (when resolve() was called)
  function() {
    alert('success')
  },
  // error (when reject() was called)
  function(reason) {
    alert('failed: ' + reason)
  }
)

We can also return an object when the task is completed. To do this, just pass the object as an argument to the resolve() function instead of nothing. Below is an example:
function myAsyncFunc() {
  var myObject = . . .
  deferredObject.resolve(myObject);
}

// then on the caller, we can use the passed object
myAsyncFunc().then(
  // success
  function(passedObj) {
    . . .
  }
);

When resolving a deferred object, we can use deep nesting functions if required. As long as the deferred object variable is accessible, this should not be an issue:
var deferredObject; // need to make sure that this deferred object variable will be accessible from inside nesting function

function myAsyncFunc() {
  // create a deferred object
  deferredObject = $q.defer();

  . . .

  nestedOne();

  // return the promise
  return deferredObject.promise;
}

function nestedOne() {
  nestedTwo();
}

function nestedTwo() {
  deferredObject.resolve();
}

Wednesday, 10 December 2014

Some Guidelines to Design Clean Controller and Service

An AngularJS controller should not be burdened with other tasks other than mediating interaction between view and data that comes from one or more services. The data model, data management and application business logic should be written in services. I also like to use controllerAs with 'this' approach. Also include as few services as possible in the controller. If a controller has too many services then this should be questioned. Instead we should try to use services that aggregate other required services inside.

Below is an example of a controller:
myApp.controller('MedicineCtrl', ['medicineService',
 function (medicineService) {
     var vm = this;
     vm.medicineNames = medicineService.medicineNames;
     vm.addMedicine = function (input) {
         medicineService.addMedicine(input);
     };
     vm.updateMedicine = function (input) {
         medicineService.updateMedicine(input);
     };
     vm.deleteMedicine = function (id) {
         medicineService.deleteMedicine(id);
     };
}]);
Of course, this is a simplified example however this should give us a picture of what a controller should be designed like.

For the service, it's recommended to have 'private' variables and functions needed and only expose publicly the ones that are necessary as service object's properties. Also whenever possible, try to design the functions to run asynchronously using AngularJS promise (will show an example in the next post). Below is an example of a service:
myApp.factory('medicineService', ['otherService1', 'otherService2', 
  function (otherService1, otherService2) {
    // 'private' variables and functions
    var _medicines = [];
    var _privateVarOne;
    var _privateVarTwo;
    
    _addMedicine = function (input) {
       . . .
       // some business logic
       . . .
    };

    _updateMedicine = function (input) {
       . . .
       // some business logic
       . . .
    };

    _deleteMedicine = function (id) {
       . . .
       // some business logic
       . . .
    };

    _anotherPrivateFunction = function () {
       . . .
       // some business logic
       . . .
    };

    // only expose publicly the required members
    return {
        medicineNames: _medicineNames,
        addMedicine: _addMedicine,
        updateMedicine: _updateMedicine,
        deleteMedicine : _deleteMedicine 
    }
}]);

Wednesday, 3 December 2014

AngularJS ControllerAs and Scope

If we set up a view and controller with controllerAs like below:
// in routing configuration
. . .
.when('/pageOne', {
        templateUrl: 'partials/page-one.html',
        controller: 'CtrlOne',
        controllerAs: 'vm'
})
. . .
// the controller
userApp.controller('CtrlOne', [function () {
    var vm = this;
    vm.nameOne = "test";
    vm.getName = function () {
        return 'aaa';
    };

    this.nameTwo = "blah";
    var nameThree = "ggg"; // not visible from outside
}]);
then we will have these scopes when the page loads:



The first scope is the root scope and the one underneath it is the scope created for the controller. As the picture shows, the variables are created as properties of 'vm' object. If we had used the traditional approach by defining variables on $scope such as $scope.myVariable = ... then these variables would be created on the first level on controller scope (not wrapped inside an object). We can also see when we use controllerAs, other variable that is defined directly not through 'this' object will not be visible from outside.


Adding a Child Controller

Let us add a child controller inside our controller. The child controller:
userApp.controller('ChildCtrl', [function () {
    var vm = this;
    vm.dataOne = 'sss';
    vm.getData = function () {
        return 'bbb';
    }
}]);
And change our view to be like this:
<div>
    Page One
    <div>
        <div>{{parentVm.nameOne}}</div>
        <div ng-controller="ChildCtrl as childVm">
            {{childVm.dataOne}}
            {{parentVm.nameOne}}
        </div>
    </div>
</div>

Now we can see that a new scope is created for the child controller:




Accessing Parent Controller's Variables

On the view, we can simply use '{{parentVm.variableName}}' to refer to a parent controller's variable.

In the child controller script function, accessing parent's variables which controller uses controllerAs is not as easy as if the parent controller had used $scope to register its properties. One way to do this is by using $scope help in the child controller. We need to inject $scope to the controller then refer to the parent controller's instance name to be able to access its variables/properties. Below is an example:
$scope.parentVm.nameOne = 'modify parent var';
//$scope.$parent.parentVm.nameOne = 'modify parent var';    // or could use $parent
The code on the first line is utilising JavaScript prototypal inheritance where it will try to find the property 'parentVm.nameOne' on the current scope then if it is not found, it will try to find on the parent scope and so on until it reaches the root scope. This AngularJS documentation 'Understanding Scope' explains it in more details.
The second code is finding the property on the parent scope. We could append many $parent if required.

If we had tried to do these below inside child controller:
vm.nameOne = 'modified';
$scope.nameOne = 'hhh';
new variables would be created on the current scope. One is on the scope's root level and the other one is inside an object. The picture below shows this:




Creating Local Variables that Hold References

If we want to create a local variable that holds reference to a variable in parent controller then we need to create that variable as an object in parent controller. This is explained as well in the referred AngularJS documentation above. For example:
// create an object variable in parent controller
vm.objVar = { name: 'aaa' };
then in our child controller:
// create the local variable in child controller
vm.childRefVar = $scope.$parent.parentVm.objVar;

// try to do some update
$scope.$parent.parentVm.objVar.name = 'jjj'; // when we update the variable in parent controller, this will reflect in both parent and local variables
vm.childRefVar.name = 'bbb'; // when we modify the local variable, this will reflect in parent variable as well


Best Practices

As we have seen above, accessing variables in parent controller is not straight forward. If you are going to have nested controllers in your view, it is recommended to use a service to share data between the controllers rather than using variables/properties in your controller.

If you do not want to use a service then I think it is better to register the variables or functions that are going to be shared on $scope rather than on 'this' object unless you are going to decide/know the controller's alias object name in advance to be used from codes inside child controller.

Thursday, 13 November 2014

Cordova Plugin is not Available when Application Starts

If you use a plugin and execute its method when your application starts and have this error:
TypeError: Cannot read property '[your_plugin_name]' of undefined at Object.[plugin_method]
then it is likely that the plugin has not been initialised fully when the method is called.

To solve this issue, wait until deviceready event is fired before calling the plugin's method.

With AngularJS, I like to wait until deviceready event is fired before loading the whole application. To do this, make sure that ng-app declaration is removed from the HTML, then bootstrap the app when deviceready event has fired. document.addEventListener is used to determine whether the event has been fired.
document.addEventListener("deviceready", function() {
    angular.bootstrap(document, ["myApp"]);
}, false);
If you want to apply this to a particular element instead of the whole HTML document (or body), you could use:
var theElement = document.findByID(...) // or document.querySelector(...);
angular.bootstrap(theElement, ["myApp"]);

Then you can call the rest scripts:
var myApp= angular.module('myApp', [. . .]);

myApp.config(
  . . .
);

Friday, 7 November 2014

Concatenating Results in SQL Query

Below is an example to concatenate results in an SQL query:
SELECT S.FirstName, S.LastName,
  STUFF( 
    ( SELECT ',' + S1.FirstName + ' ' + S1.LastName FROM Student S1 WHERE S1.FirstName = S.FirstName FOR XML PATH('') ), 
    1, 
    1, 
    ''
  ) AS AnyStudentsWithSimilarNames
FROM Student S

In the example, we use FOR XML PATH('') to concatenate the result from multiple rows into a single value.

We also use STUFF() function to simply remove the first occurrence of ',' character. The syntax is STUFF( expression, starting_character_position, length, replace_with_expression ).

If we have '<', '>' or '&' characters in our projection and want to avoid those getting encoded, we can replace the codes inside STUFF() function to:
(SELECT ... FOR XML PATH(''), TYPE).VALUE('.','VARCHAR(MAX)')
Here we add TYPE to have the query with FOR XML PATH() returns XML data type then we use VALUE() function to get the value. Both are used as a work around to avoid the characters getting encoded.

Thursday, 23 October 2014

Adding ngCordova Plugin to Visual Studio Cordova Project

We will see how to add a plugin from ngCordova which has a collection of Cordova API plugins wrapped in AngularJS. ngCordova will help even more Cordova developers who are using AngularJS.

1. First, include ng-cordova.js or ng-cordova.min.js file into our project structure. We can use bower to install that or download the zip file from its GitHub repository then find the js file inside.

2. On our project main page, add a reference to it before the reference to cordova.js file.
<script src="some_path/ng-cordova.min.js"></script>
<script src="cordova.js"></script>

3. Include 'ngCordova' in our app module. For example:
var myApp = angular.module('myApp', ['ngCordova', . . .]);

4. Add the intended plugin wrapped by <vs:feature></vs:feature> inside <vs:features> node in our project config.xml file like below:
<vs:features>
  <vs:feature>plugin_id@version_number</vs:feature>
  <vs:feature>plugin_2_id@version_number</vs:feature>
  . . .
</vs:features>
Right click config.xml file then select View Code to do this.

To find the plugin Id and version number, we can check from plugins.cordova.io site or from the plugin.xml file on the plugin repository site. However if we are getting the information from plugin.xml file, that will always be the latest version which sometimes is not the stable one.

An example for the latter one, say we would like to use Local Notification plugin. Go to its site https://github.com/katzer/cordova-plugin-local-notifications then open plugin.xml file located on the root. Inside the plugin element there are 'id' and 'version' attributes.

When building the project, Visual Studio will download the plugin and add to the project if it has not done so.


5. Inject the plugin service into our controller then we can start using it.
For example, to use Local Notification, we need to inject $cordovaLocalNotification like this:
myApp.controller('MyCtrl', ['$cordovaLocalNotification', . . . ,
  function ($cordovaLocalNotification, . . .) {
  . . .
}]);

Friday, 10 October 2014

Basic Navigation in Ionic

On this post we will see how to do basic navigation in Ionic Framework.

1. First we need to configure the routes in AngularJS:
app.config(function($stateProvider, $urlRouterProvider) {
  $stateProvider
  .state('home', {
    url: '/',
    templateUrl: 'home.html'
  })
  .state('pageOne', {
    url: '/page1',
    templateUrl: 'one.html'
  })
  .state('anotherPage', {
    url: '/whatever',
    templateUrl: 'myhtml.html'
  });
  
   $urlRouterProvider.otherwise("/");
});
In the example we use UI Router to manage our routes. Each route has a state name, a defined url and an actual path for the view content. In the end, we also define the default url to be called when a url targeted does not match any in configurations.


2. Then on our main page, we just need to use
<ion-nav-view></ion-nav-view>
It will be useful to add a navigation bar with back button and also to have an animation effect like this:
<ion-nav-bar class="bar-positive">
        <ion-nav-back-button class="button-icon ion-arrow-left-c">
        </ion-nav-back-button>
    </ion-nav-bar>

    <ion-nav-view animation="slide-left-right"></ion-nav-view>
When we use Ionic navigation back button, the scripts behind it automatically do the job in storing page histories and pulling out the previous page as well as redirecting to the page when clicking the element.


3. Finally create each partial view using
<ion-view>
  <ion-content>
    . . .
  </ion-content>
</ion-view>


For a complete working example, please see here in Plunker.

Friday, 3 October 2014

Navigation in MVVM Light using Messenger

There are a few ways to implement navigation in MVVM Light based application. One of them is to use the Messaging framework of the toolkit. We will see a simple example of how to do this on Windows Phone.

1. First, in our view, we need to register to listen for a message that we want to receive :
Messenger.Default.Register<uri>(
this,
"MyToken",
(uri) => NavigationService.Navigate(uri)
);
We can put this in the view constructor or OnNavigatedTo() method. This code is saying that I want to register to receive any message that delivers uri type that uses 'MyToken' token. If there is any then I will execute an action which in this case is calling NavigationService.Navigate(uri).


2. Then in the view model, we need to create a command to trigger the message that will be broadcasted.
We add a RelayCommand property for a navigation command:
public RelayCommand NavigateCommand { get; private set; }
Then in the view model constructor we initialise that (or could be on the property getter above):
NavigateCommand = new RelayCommand(() =>
{
Messenger.Default.Send<uri>(new Uri("/PageName.xaml", UriKind.Relative), "MyToken");
});


3. Finally bind the command property to a control on the view xaml file using:
Command="{Binding NavigateCommand}"


Soon we will have many repetitive codes in our views, so we could put the codes to register for the message in a base class like this:
public class BasePage : PhoneApplicationPage
{
 protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
 {
 Messenger.Default.Register<uri>(this, "MyToken", uri => NavigationService.Navigate(uri));
 base.OnNavigatedTo(e);
 }

 protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
 {
 Messenger.Default.Unregister<uri>(this);
 base.OnNavigatedFrom(e);
 }
}
So we just need to make our views inherit from this class.

On our xaml files, we also need to replace
<phone:PhoneApplicationPage
to
<phone:BasePage

and also
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
to
xmlns:phone="clr-namespace:YourNamespace"


Another way to do navigation is by creating our custom navigation service to be used in our view models. This nice article, explains how to implement it in details.

Thursday, 2 October 2014

Getting Started with Cordova and Ionic in Visual Studio

On this post, we will see how to install Visual Studio Apache Cordova tool and Ionic framework and get started with a sample application.

1. First we need to download and install Apache Cordova tool from here. At the time of writing, the version is CTP 2.0.

2. Then once completed, open Visual Studio to create a new project. On the New Project dialog, go to JavaScript project templates then Multi-Device Hybrid App. Select Blank App (Apache Cordova) then create a project.

3. Install Ionic through NuGet. At the time of writing, the latest version is v1.0.0.0-beta.1. This will add many AngularJS and Ionic files into our project.

4. Install Ionic on local machine so that we could create some sample applications with particular templates and use some of the files in our project. To do this, open Node.js command prompt then run this command:
npm install ionic -g
-g is used to install the package globally

5. On the command prompt, go to a directory where you want to have Ionic sample applications then run this command:
ionic start SideMenuAppExample sidemenu
This command will generate a sample Ionic application with side menu navigation.

6. Go to the generated app folder then to 'www\js' folder then copy app.js and controllers.js into our project.

7. Also copy the whole 'templates' folder and its content into our project.

8. Then on our project index.html file:
- add a reference to 'Content/ionic.css'
- add a reference to 'scripts/ionic.bundle.js'
- add references to the two JavaScript files that we have copied over (app.js and controllers.js)
- add 'ng-app="starter"' in the body
- add <ion-nav-view></ion-nav-view> inside the body content

Once finished, we will have something like this on our index.html:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>BlankCordovaApp2</title>

    <link href="Content/ionic.css" rel="stylesheet" />
    <link href="css/index.css" rel="stylesheet" />
</head>
<body ng-app="starter">
    <ion-nav-view></ion-nav-view>


    <!--library scripts references-->
    <script src="scripts/ionic.bundle.js"></script>
    <script src="cordova.js"></script>
    <script src="scripts/platformOverrides.js"></script>
    
    <!--custom scripts references-->
    <script src="app.js"></script>
    <script src="controllers.js"></script>
</body>
</html>

Then run the application. We should see a sample app with side menu running.