In this short tutorial, I will show how to use AngularJS in ASP.NET MVC. I hope that you enjoy this short tutorial and this is helpful.

Application Inception

While Angular is a framework for the modern Single Page App, I have found that a lot of our MVC applications call for a collection of these “ng-apps”. In this instance they typically don’t include the client side routing.

Please See Sample Application

The image to the right is the file structure for a sample airplane scheduling app. There are three sections:

  Home (simple js) - A simple calendar showing flights
  Details (angular) - Information about a single flight
  Manage (angular) - A place for settings, pilots, etc...

Bundle Configuration

While asset bundling is a great feature of ASP.Net, it is easy to get carried away. When I came on there were a lot of projects that just included all the js files for the entire application in a single ScriptBundle. This was one of the first places I set my sights.

I decided that a lot of the services would be shared, so they could go in their own Angular module and in their own ASP Bundle. Then each mini-app could get it’s own module and bundle. Lets take a look at theBundleConfiguration.cs file.

using System.Web.Optimization;

namespace Jobney.App.Web
{
    public class BundleConfig
    {
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/js-base").Include(
                        "~/Scripts/libs/jquery-{version}.js",
                        "~/Scripts/libs/bootstrap.js",
                        "~/Scripts/libs/select2.js",
                        "~/Scripts/libs/bootstrap-datepicker.js",
                        "~/Scripts/libs/respond.js",
                        "~/Scripts/libs/lodash.js",
                        "~/Scripts/endless.js"
                        ));

            bundles.Add(new ScriptBundle("~/bundles/ng-base").Include(
                        "~/Scripts/libs/angular/angular.js",
                        "~/Scripts/libs/angular/ui-router.js",
                        "~/Scripts/libs/angular/ui-bootstrap-custom-0.9.0.js",
                        "~/Scripts/libs/angular/ui-bootstrap-custom-tpls-0.9.0.js",
                        "~/Scripts/libs/angular/angular-animate.js",
                        "~/Scripts/libs/angular/toaster.js"
                        ));

            bundles.Add(new ScriptBundle("~/bundles/ng-shared-services")
                .IncludeDirectory("~/Scripts/apps/shared/", "*.js"));

            bundles.Add(new ScriptBundle("~/bundles/ng-manage-app")
                .IncludeDirectory("~/Scripts/apps/manage/","*.js"));

            bundles.Add(new ScriptBundle("~/bundles/ng-tripinfo-app")
                .Include(
                    "~/Scripts/libs/jquery-ui.js",
                    "~/Scripts/libs/angular/sortable.js",
                    "~/Scripts/libs/angular/select2.js",
                    "~/Scripts/libs/angular/ngAutocomplete.js"
                )
                .IncludeDirectory("~/Scripts/apps/tripinfo/", "*.js"));

            bundles.Add(new StyleBundle("~/Content/css/base").Include(
                      "~/Content/css/bootstrap.css",
                      "~/Content/css/datepicker3.css",
                      "~/Content/css/select2.css",
                      "~/Content/css/toaster.css",
                      "~/Content/css/select2-bootstrap.css",
                      "~/Content/css/font-awesome.css"
                    ));
            bundles.Add(new StyleBundle("~/Content/css/custom").Include(
                      "~/Content/css/endless.css",
                      "~/Content/css/endless-skin.css",
                      "~/Content/css/site.css"));
        }
    }
}

Then using the bundles, say in the manage app, it would look like this:

@model Jobney.Casm.Web.Models.ManageDataBootstrapper
<div data-ng-app="Jobney.Casm.ManageApp" data-ng-controller="ManageAppCtrl">
    <ul class="tab-bar grey-tab">
        <!-- content here -->
    </ul>

    <div data-ui-view></div>
</div>

@section scripts
{
    <!-- Start ng-base -->
    @Scripts.Render("~/bundles/ng-base")

    <!-- Start ng-shared-services -->
    @Html.Partial("_SharedServices")

    <!-- Start ng-manage-app -->
    @Html.Partial("_ManageAppSetup", Model)
}

Services Need Data And Data Needs Urls

As an ASP.Net MVC developer, you are probably used to letting the routing engine create urls for you when you need them. And why not? Who knows what crazy routing constraints the client/pm/other developers decided needed to be in your application. And with Razor helpers, this is pretty easy. Angular shouldn’t have to try hard to figure out those rules. So how do we combine these two worlds?

@section scripts
{
    app.constant('RouteConfig', {
        base: '@Url.Content("~/")',
        project: {
            all: '@Url.Action("All", "Project")',
            details: '@Url.Action("Details", "Project")',
            post: '@Url.Action("Post", "Project")'
        },
        vendor: {
            category: '@Url.Action("GetByCategory", "Vendor")',
            details: '@Url.Action("GetById", "Vendor")',
            getProductRating: '@Url.Action("GetByProduct", "Rating")'
        },
        resolve: function (url) {
            return this.base + url;
        }
    });
}

Such http. Many calls.

In the manage app we are going to need some data. When the situation calls for it, I don’t mind sending that data down with the app. I think I took this idea from John Papa or one of those PluralSight authors. Basically, I just use JSON.Net to serialize my dataset on the page. Let’s take a look at it.

@model Jobney.Casm.Web.Models.ManageDataBootstrapper

<script>
    (function () {
        'use strict';

        var app = angular.module('Jobney.Casm.ManageApp', [
            'ui.router',
            'ui.bootstrap',
            'Jobney.Casm.SharedServices'
        ]);

        app.factory('BootstrappedData', [function() {
            var service = {};

            service.pilots = @Html.Raw(Model.Pilots);
            service.passengers = @Html.Raw(Model.Passengers);
            service.airplanes = @Html.Raw(Model.Airplanes);
            service.settings = @Html.Raw(Model.Settings);

            return service;
        }]);       

    })();
</script>

@Scripts.Render("~/bundles/ng-manage-app")