Click here to Skip to main content
15,891,567 members
Articles / Web Development / HTML
Tip/Trick

MVVM with MVC-Razor and AngularJS Global Controllers

Rate me:
Please Sign up or sign in to vote.
4.63/5 (12 votes)
2 Feb 2015CPOL4 min read 51.4K   1.1K   24   15
Using angularjs global controllers and MVC Razor to divide page (load) rendering between server and browser

Introduction

In this tip, I am going to explain how to build ASP MVC SPA using AngularJs global controllers.

Last few years, we have seen the emergence of plenty of JavaScript frameworks for building client side SPA and probably the most known is AngularJs .The main concept behind it is to load all application files to the browser and run it once in the client side using an API server side to load data. This is the opposite of what we call traditional web applications that renders entirely (most part) on the server side. This design is not new, I would say SilverLight, Flash JavaApplets..... had done the same. And I'll not tell about their success. What changed is now we use JavaScript instead of C#, JAVA, Actionscript.

Those framework are touted (evengelised) using a small demo application called TodoMVC and running this application, all things run well and we can see the magic of data binding ,DI, productivity and ....

But when you develop a large application mainly an enterprise application using those frameworks, your smiles and enthusiasm will not be the same.

Here below, I will list some problems I encountered while implementing large web applications using AngularJs and some critics that I would like to expose to the community.

  • Loading all JS files to the browser is not very wise
  • Rendering all pages on client side is not an ideal solution: many users of the application don't have extras machines and processors. A lot of them run 2Go RAM or less machines (not all internet users work in Google Inc). I have seen AngularJs application leaking memory and not rendering on small machines.
  • Security: All JS are visible on the browser (they say they are mimified and linted and...) but still are accessible for every one and every one can see the code logic and exploit it for an attack.
  • All application routes all exposed in JS file. Every one authorized or not can see all the routes
  • Caching everything: Some JS files or HTML files contain sensitive data but some people cache everything they say to enhance performance but what about security
  • HTTP calls: Doing with those framework SPAs you have not to count the client/server round trip ! And talking performance the client/server call is expensive.
  • Lot of web controls are JQuery based controls so, porting them into those frameworks is not so peaceful
  • Controlling different environments (legacy browsers, mobile, desktop...) is done on the client side

If I summarize, I would like to say that I faced a lot of limitations working with the new JS frameworks, mainly security, performance and productivity .

Background

By this contribution, I would like to resolve some difficulties I faced during the implementation of AngularJs SPA:

  • Divide the page load: combine the server side rendering and client side rendering
  • Reduce the Client/server round trips: the server will send all that the client needs at once
  • Security: Send to the client only what it needs
  • Load only what the client needs
  • Control different environments on the server

For the last point, some people proposed using RequireJS to load asynchronously but this will only defer the problem because RequireJS loads JS files but doesn't remove them.

In this, I will use ASP.NET MVC with Razor and AngularJS with global controllers.

AngularJS globals Controllers work like this we can inject a controller directly in the view, some are like this:

HTML
<script>
function thispageCtrl($scope)
{
  $scope.message="hello global";
}
</script>
<div ng-controller="thispageCtrl">
    <p>{{message}}</p>
</div> 

In Angular app, if we have any route that points this page, it will render normally.

In AngularJs 1.3.... we must specify this in app config and add a single line like this:

JavaScript
//
.config(['$controllerProvider', function ($controllerProvider) {
    $controllerProvider.allowGlobals();
  }])
//

Using the Code

I attached with this tip a running Visual Studio ASP MCV application.

Image 1

The App_JS folder contains the Angular application in the root we have config.js file where we configure simple user routes and config-admin.js to configure admin routes.

config.js file looks like this:

JavaScript
//
(function (win, ng) {

'use strict';
  ng.module('app')
   .constant('routes', [
{
            url: '/',
            config: {
              templateUrl: 'home/home',
              settings: {
              }
            }
          }, {
            url: '/contact',
            config: {
              templateUrl: 'home/contact',
              settings: {
              }
            }
          }, {
            url: '/about',
            config: {
              templateUrl: 'home/about',
              settings: {
              }
            }
          }, {
            url: '/Employee',
            config: {
              templateUrl: 'Employee/index',
              settings: {
              }
            }
          }  , { url: '/Employee/details/:id',
            config: {
              templateUrl: function (params) {
                return 'Employee/details/' + params.id;
              },
              settings: {
              }
            }
          } 
   ]);
})(this, angular)

//

Another Js file of the App_Js folder is the traditional App.js that looks like this:

JavaScript
//
 (function (window, ng) {
var app = ng.module('app', [
       'ngAnimate',        // animations
         'ngRoute',          // routing
         'ngSanitize',       // sanitizes html bindings (ex: sidebar.js)
  ])
.config(['$routeProvider', 'routes', function ($routeProvider, routes) {
    routes.forEach(function (r) {
      $routeProvider.when(r.url, r.config);
    });
    $routeProvider.otherwise({ redirectTo: '/' });
  }])
.config(['$controllerProvider', function ($controllerProvider) {
    $controllerProvider.allowGlobals();
  }])
 .config(['$provide', function ($provide) {
      $provide.decorator('$exceptionHandler',
          ['$delegate', 'logger', function ($delegate, logger) {
            return function (exception, cause) {
              $delegate(exception, cause);
              var errorData = { message: exception, cause: cause };
              logger.error(errorData)
            };
          }]);
}]).config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
  }])
})(this, angular)

//

in the other side 

On the other side, we can see the page rendering with Razor and AngularJS.

This is just an example of rendering the EmployeeList.

JavaScript
//
@using razorAngular.Resources 
@model razorAngular.Models.EmployeeListViewModel
@{
    Layout = null;
}
<script>
    function employeeListVM($scope,$rootScope) {
        $rootScope.title="@Messages.Employees";
        $scope.vieModel= @Html.Raw(Html.ToJson(Model));
        $scope.sortby = function (item) {
            return item[$scope.orderBy];
        }
    }
</script>

<div ng-controller="employeeListVM">
 <h2>@Messages.Employees</h2>
    <p><strong>@Messages.Total : </strong>{{vieModel.total}}</p>
    <table class="table table-hover">
        <thead>
            <tr>
                <th ng-repeat="header in vieModel.headers">
        <a href="javascript:;" 
        ng-click="$parent.orderBy=$index+1">{{header}}</a></th>
                <th>Details</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="employee in vieModel.data| orderBy:sortby track by $index ">
                <td ng-repeat="item in employee.slice(1) track by $index">{{item}}</td>
                <td>
                    <a href="#/Employee/details/{{employee[0]}}" 
            class="glyphicon glyphicon-eye-open">Details</a>
                    <a href="#/Employee/details/{{employee[0]}}" 
            class="glyphicon glyphicon-edit">Edit</a>
                </td>
            </tr>
        </tbody>
    </table>
</div>

//

As is visible in the above code, we can see the Razor view model converted to JSON and then send to the browser.

Points of Interest

  • Divide the page rendering between the server and the client
  • Only one client/server Http trip to render a page
  • All sensitive data is controlled server side

Hope this will be useful!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionerror to open solotion in VS 1012 and 2013 Pin
rochdibouazza10-Feb-15 1:17
professionalrochdibouazza10-Feb-15 1:17 
AnswerOpen Visual studio as Admin Pin
lakhdarr10-Feb-15 4:41
lakhdarr10-Feb-15 4:41 
Questionwrap javascript in self invoking function Pin
skaus1235-Feb-15 20:29
professionalskaus1235-Feb-15 20:29 
AnswerRe: wrap javascript in self invoking function Pin
lakhdarr6-Feb-15 7:36
lakhdarr6-Feb-15 7:36 
Questiondo a spelling check Pin
Rahman Mahmoodi3-Feb-15 10:14
Rahman Mahmoodi3-Feb-15 10:14 
I couldn't continue reading due to the grammar and spelling errors. Please do a spell check next time!!
AnswerRe: do a spelling check Pin
lakhdarr3-Feb-15 10:21
lakhdarr3-Feb-15 10:21 
GeneralThis is not the correct way to use the AngularJS Pin
lvendrame3-Feb-15 9:22
lvendrame3-Feb-15 9:22 
GeneralRe: This is not the correct way to use the AngularJS Pin
lakhdarr3-Feb-15 10:12
lakhdarr3-Feb-15 10:12 
GeneralRe: This is not the correct way to use the AngularJS Pin
Pascen27-Feb-15 10:54
Pascen27-Feb-15 10:54 
GeneralThat is your opinion Pin
lakhdarr27-Feb-15 12:43
lakhdarr27-Feb-15 12:43 
GeneralGood Pin
Riza Marhaban3-Feb-15 4:50
Riza Marhaban3-Feb-15 4:50 
GeneralRe: Good Pin
lakhdarr3-Feb-15 5:10
lakhdarr3-Feb-15 5:10 
GeneralNo Source Pin
Garvice2-Feb-15 17:43
Garvice2-Feb-15 17:43 
GeneralRe: No Source Pin
lakhdarr2-Feb-15 21:24
lakhdarr2-Feb-15 21:24 
GeneralRe: No Source Pin
lakhdarr2-Feb-15 21:37
lakhdarr2-Feb-15 21:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.