Friday, October 31, 2014

AngularJS & Download File using WebAPI

As you know AngularJS routing overwrites the relative urls in a hyperlink so that AngularJS can handle all the requests. This sometimes causes problems. In my scenario I want to download a file when user clicks on a hyperlink in my grid. AngularJS is not sending this request to the server as a result I am unable to serve the file user wants to download.

Here is my hyperlink code that I used in the grid.

<a href="/api/download/1">Download File</a>

As you see the above hyperlink calls an webapi which in turns returns a word document that needs to be downloaded. As mentioned above clicking on this hyperlink does not download the file.
The solution for this issue is very simple, we just need to specify the target of the “a” tag as shown below

<a target="_self" href="/api/download/1">Download File</a>

Please see my other blog on how to download a file from Web API


Thursday, October 30, 2014

AngularJS UI-Router and Page title

In my previous blog, I wrote about on how to set Page title when using AngularJS routing. In this blog I will write about on how to do the same when we are using ui-router. If you haven’t read my previous blog, here is my requirement: when the user navigates from one page to another using angular routing mechanism, I want to set the page title and I would like to set this in an unobtrusive manner.

The approach and the code is almost similar in setting the page title using either with angularjs router or ui-router. But there is a minor difference due to the syntactical differences between these two routers.

Here is the code for defining the title attribute in the router

    $stateProvider
        .state("dashboard", {
            url: "/",
            title: "Dashboard",
            templateUrl: "/app/dashboard/dashboard.html",
            controller: "dashboard",
            controllerAs: "vm",
            resolve: ['dashboardService', function (dashboardService) {
                return dashboardService.resolve();
            }]
        })
        .state("login", {
            url: "/login",
            title: "Login",
            templateUrl: "/app/account/login.html",
            controller: "login",
            controllerAs: "vm",
        })
        .state("patient", {
            url: "/patient/:patientid",
            title: "Patient",
            templateUrl: "/app/patient/patient.html",
            controller: "patient",
            controllerAs: "vm",
            resolve: ['$stateParams', 'patientService', function ($stateParams, patientService) {
                return patientService.resolve($stateParams.patientid);
            }]
        })

Once the route is defined with the title attribute, I can set the window title on the state change event

        $rootScope.$on('$stateChangeSuccess', function (evt, toState, toParams, fromState, fromParams) {
            $window.document.title = toState.title;
        });

As you see we can unobtrusively set the page title by using either routers

AngularJS Routing and Page title

I came across a scenario where I would like to set the page title for each route in my angularjs app. For example if the user is in the dashboard, I want to set the page title as dashboard and when the user navigates to the patient page, I would like to set the page title as Patient. Obviously I would like to set this in an unobtrusive way.

In order to accomplish this first I defined a custom attribute called “title” in the angularjs routing as shown below:

    $routeProvider
        .when("/", {
            title: "Dashboard",
            templateUrl: "/app/dashboard/dashboard.html",
            controller: "dashboard",
            controllerAs: "vm",
        })
        .when("/login", {
            title: "Login",
            templateUrl: "/app/account/login.html",
            controller: "login",
            controllerAs: "vm",
        })
        .when("/patient/:patientid", {
            title: "Patients",
            templateUrl: "/app/patient/patient.html",
            controller: "patient",
            controllerAs: "vm",
            resolve: ['patientService', function (patientService) {
                return patientService.resolve();
            }]
        })

For each of the routes defined in my routing, I added a title attribute that will be set as a page title. After defining the title, I am setting this title on the route change event of the angularjs routing as shown below

        $rootScope.$on('$routeChangeSuccess', function () {
            $window.document.title = $route.current.title;
        });

With this approach I was able to set the title of each page at a module level (not going inside each page).

Monday, October 13, 2014

Typical AngularJS routing using ui-router

Last month I blogged about a typical routing using AngularJS router. AngularJS routing is good and works for most of the scenarios. In some situations where you need to do nested routing or some advanced routing, the current implementation fells short. It seems that the AngularJS 2.0 routing is robust and should cater to all the requirements. But that’s not going to be out soon. In the meanwhile we have an excellent routing module called ui-router. There is an excellent article on how to use this router. I provided the link to this article at the end of my blog.

ui-router supports and caters all the requirements AngularJS default routing provides. Hence I recommend to use this routing for all your scenarios. In this blog I will show my simple routing configuration using ui-router. In my subsequent blogs I will dig deeper into the nested routing and other ui-router tasks.

Here is my complete code for defining a route (for simplicity I kept only one route and removed all other routes)

'use strict';

angular.module('pos').config(routeConfig);
routeConfig.$inject = ['$stateProvider', '$urlRouterProvider', '$locationProvider'];

function routeConfig($stateProvider, $urlRouterProvider, $locationProvider) {

    $stateProvider
        .state("patient", {
            url: "/patient/:patientid",
            title: "Patient",
            templateUrl: "/app/patient/patient.html",
            controller: "patient",
            controllerAs: "vm",
            resolve: ['$stateParams', 'patientService', function ($stateParams,
                     patientService) {
                return patientService.resolve($stateParams.patientid);
            }]

    $locationProvider.html5Mode(true);

    $urlRouterProvider.when('', '/login')

}
As you see in the above code, I defined a state called “patient” and defined all the parameters for this state. Here are the salient features of this route definition
            title: "Patient",
This is not the attribute or property of the ui-router. I am using this to set the window title (which is shown in the browser toolbar). This is similar to setting the title tag. I will blog about this in my next blog.
            controllerAs: "vm",
I like the controllerAs feature. It eliminates the need of using $scope in my code and make my code clean.

            resolve: ['$stateParams', 'patientService', function ($stateParams,
                     patientService) {
                return patientService.resolve($stateParams.patientid);
            }]
This is one of the important features of my routing. I don’t want to burden my compiler with fetching the data from server and activities other than rendering. As these are model or domain specific, I create a service for each controller to handle these activities. As you know in most scenarios you need to fetch data from the server before rendering the page, “resolve” is designed for that activity. Until resolve returns (fetches the data or any other activity) Angular waits and will not render the page. Resolve option also helps avoiding the FOUC. Please see my blog on this for further details
    $locationProvider.html5Mode(true);
I am also using the html5Mode which makes my urls simple. As you know for older browsers the router automatically fallback to using “#”.
    $urlRouterProvider.when('', '/login')
Finally I am using the $urlRouterProvider to specify a default start view. In this scenario I am redirecting user to the login page.

As you see my routing with ui-router is almost similar to that of the router provided by angular. With this set, I can start using advanced routing features.

Here is a detailed blog on the using Angular ui-router Diving deep into the AngularUI Router