Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fairytale about mvc, require.js and angular. is there happily ever after?

So. Once upon a time there were four magical creatures: asp.net mvc, require.js and angular. And one wise wizard decided to put them in the same house, and let for every single view of asp.net to have its own "code-behind" javascript file;

first he added to the _Layout.cshtml

 <script  data-main="/main" src="~/Scripts/require.js"></script>

and then he created main.js in the root:

require.config({
    baseUrl: "/Scripts/",
    paths: {
        'jquery': 'jquery-1.9.1.min',
        'jquery-ui': 'jquery-ui-1.10.2.custom.min',
        'angular': 'angular.min',
        'ng-grid': 'ng-grid-2.0.2.debug'
    },
    shim: {
        'jquery': { exports: "$" },
        'underscore': { exports: "_" },
        'jquery-ui': ['jquery'],
    },
});
 // Standard Libs
require(['jquery','jquery-ui','underscore','angular']);

nothing fancy and magical yet. But then he created an html helper as such:

public static MvcHtmlString RequireJs(this HtmlHelper helper)
{
    var controllerName = helper.ViewContext.RouteData.Values["Controller"].ToString(); // get the controllername 
    var viewName = Regex.Match((helper.ViewContext.View as RazorView).ViewPath, @"(?<=" + controllerName + @"\/)(.*)(?=\.cshtml)").Value; //get the ViewName - extract it from ViewPath by running regex - everything between controllerName +slash+.cshtml should be it;

// chek if file exists
    var filename = helper.ViewContext.RequestContext.HttpContext.Request.MapPath("/Scripts/views/" + controllerName.ToLower() + "-" +
                                                                  viewName.ToLower()+".js");
    if (File.Exists(filename))
    {
        return helper.RequireJs(@"views/" + controllerName.ToLower() + "-" + viewName.ToLower());   
    }
    return new MvcHtmlString("");
}

public static MvcHtmlString RequireJs(this HtmlHelper helper, string module)
{
    var require = new StringBuilder();
    require.AppendLine(" <script type=\"text/javascript\">");
    require.AppendLine("    require(['Scripts/ngcommon'], function() {");
    require.AppendLine("        require( [ \"" + module + "\"] );");
    require.AppendLine("    });");
    require.AppendLine(" </script>");

    return new MvcHtmlString(require.ToString());
}

and then he could use it in _Layout.cshtml just like that:

   @Html.RequireJs()

and if you were listening carefully to the story, you probably noticed that there was also Scripts/ngcommon.js file to manually bootstrap angular.js and have commonly used angular directives and services

require(['angular', 'jquery'], function() {
    angular.module("common",[]).directive('blabla', function() {
        return {
            restrict: 'A',
            scope: { value: "@blabla" },
            link: function(scope, element, attrs) {     }
        }
    });

    //manually bootstrap it to html body
    $(function(){
        angular.bootstrap(document.getElementsByTagName('body'), ["common"]);
    });
});

And here comes the magic: from now on if it was a javascript file in \Scripts\views named as controllerName-viewName.js as home-index.js for Home\Index.cshtml it would be automagically picked up by require.js and loaded. Beautiful isn't it?

But then the magician thought: What If I need to load something else (like ng-grid) and that something should not be injected into common angular module because not all the pages will be using it. Of course he could always manually bootstrap another module into a page element in each code-behind javascript where he needed, but he's not wise enough to find answer to the question: Is it possible to inject some angular.js component (like ng-grid) directly into a controller, without having it as a part of the app module?

like image 712
iLemming Avatar asked Mar 27 '13 15:03

iLemming


People also ask

Is MVC better than Angular?

Both ASP.NET MVC and AngularJS has their own purposes and advantages. As with your specific question, AngularJs is better for SPA (Single Page Applications), where as ASP.NET MVC is a full fledged server side Application which can contain WebAPIs, Routing engine as well as HTML emitting Views.

Why use Angular instead of MVC?

Angular does away with the problem of mixing client and server code within the same file. Razor syntax allows the developer to embed client and server code within the same file and to use server-side logic to control the client-side presentation. Angular decouples the client-side processing completely from the server.

Can we use AngularJS in ASP.NET MVC?

Go to AngularJS website and download. Click on the Download link to download the latest version of AngularJS library. Click on ASP.NET Web Application, rename the application and hit “ok” button at bottom right. Choose empty template in next window and click on “ok” button.

What is the difference between MVC and Angular?

To more directly answer your actual question, the main difference between the two is that one is an MVC pattern for the server, and the other is an MVC pattern for the browser. Angular actually likes to call it an "MVW" pattern, where the "W" stands for "Whatever".


1 Answers

If I understand magician's idea right, then it is possible to go on by splitting your application into sub-modules being defined as a collection of components.

It will work if he sets up dependencies for main myApp module like:

var myApp = angular.module('myApp', ['Constants', 'Filters', 'Services', 'Directives', 'Controllers']);
myApp.Constants = angular.module('Constants', []);
myApp.Controllers = angular.module('Controllers', []);
myApp.Filters = angular.module('Filters', []);
myApp.Services = angular.module('Services', []);
myApp.Directives = angular.module('Directives', []);

Then each of sub-modules: Services etc. - can be extended with single component, like:

myApp.Controllers.controller('MyController', function () {});
myApp.Services.factory('myService', function () {});
myApp.Directives.directive('myDirective', function () {});
myApp.Filters.filter('myFilter', []);
myApp.Constants.constant('myConstant', []);

That way main application module is loaded with several sub-modules, but each structure is not important. It makes possible to include individual controllers, services, directives and filters on each page served from back-end - magician just needs to be sure that all needed dependencies are loaded.

like image 175
Dmitry Evseev Avatar answered Nov 15 '22 06:11

Dmitry Evseev