Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I've been doing a lot of research on implementing a SPA with AngularJS on MVC, but I think I'm missing something. Do I need a MVC controller for each View still, or should angular be able to grab the cshtml or html file to render on the initial page without having an MVC controller?

Essentially I have

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

Which returns my index page which is just

<div data-ng-view></div>

It is also loading a layout with the Index page that has my menu on it with all of the links, as well as all of the script files. When I click a link such as:

<a href="/Home/ChangeLog">Change Log</a>

Which contains

<h2>{{Changes.Title}}</h2>
<div>{{Changes.Version}}</div>

It fails to load anything because it's trying to reach out to the MVC controller. If I have an MVC controller returning a partial view, it returns just the partial view as a whole page load. My angular app file is this:

var myApp= angular.module("myApp.WebConsole", ['ngRoute']);

myApp.controller("IndexController", IndexController);

var configFunction = function ($routeProvider, $locationProvider, $httpProvider) {

$routeProvider.when("/Home/Index",
    {
        templateUrl: "Home/Index.cshtml",
        controller: IndexController
    });

$routeProvider.when("/Home/ChangeLog",
    {
        templateUrl: "Home/ChangeLog.cshtml",
        controller: IndexController
    });
$locationProvider.html5Mode(true);
}

configFunction.$inject = ["$routeProvider", "$locationProvider", "$httpProvider"];

myApp.config(configFunction);

And the indexcontroller.js file is:

var IndexController = function ($scope) {
    $scope.Heading = "Index Page";
    $scope.Changes = {
        Title: "Changes",
        Version: "1.0"
    };
}

IndexController.$inject = ['$scope'];

The js files are in a separate folder. The views are in the standard MVC folder structure.

What am I missing about how this works? I would expect that clicking the link would go to retrieve the cshtml file or even just an html file and render the html in the div with the data-ng-view tag on it. Should I not be using Razor views (perhaps part of the problem since I expect the MVC controller would need to render the code data, if any)? Though I still have the same issue of not finding the page if I use just html.

Edit 2: Ok, so I've partially figured this out, the problem is using

$locationProvider.html5Mode(true);

Without this, if I make the link on the menu

<a href="/#/Home/ChangeLog">Change Log</a>

Then everything seems to work ok. I believe that is also the expected format for links using Angular. Is there some magic to making MVC and Angular routing with html5Mode enabled?

share|improve this question
    
Just FYI: I always put all AngularJS stuff ( scripts + htmls ) into a folder, say /app and then do an IgnoreRoute on that folder. I don't want serve some HTML for Angular by starting ASP.NET MVC and returning a partial view. –  spike Feb 3 at 16:59

2 Answers 2

You want to use something more like Home/Index#/Changelog -- the MVC routing stops at Index, and the Angular "picks up" after the #.

There are lots of examples if you search for "mvc angular routing", but that's the idea.

share|improve this answer

You are right, the problem is you are using the html5mode(true) which won't use # urls and so will make a browser request to the server first. If you want to continue using the html5mode=true, you need to do is force ASP.NET MVC to direct all those angular url's to the same page (your angular app home page). Then when the page loads on the client, angular routing will take over and route to the right view.

One way you can do this is with a "catchall" MVC route.
Assuming you angular app is started at /Home/Index, edit your RouteConfig.RegisterRoutes methods and add this route:

routes.MapRoute(name: "My angular webapp",
url: "Home/{*catchall}",
defaults: new { controller = "Home", action="Index", id=UrlParameters.Optional }
);

This will make all requests to /Home/anything return the Home/Index view. So you may want to use another controller for your angular app, in case you want to have other urls under Home handled by MVC.

share|improve this answer
    
So I saw this solution here: link but I'm getting some strange results. When I click a link that is now <a href="Home/Changelog"></a> as explained in the link, I get what I think is the expected result of tacking on "home/changelog" to the url each time I click it, so eventually you get /home/home/home/home/changelog. There are no errors when this happens, but no data is loaded from the template page. –  hakenmt Feb 3 at 19:43
    
If I use <a href="/Home/Changelog"></a> the url forming is ok, but I still get no data returned to the page. It also seems that on every click using this method that a full page load is incurred since essentially every click to an Angular controller is really going to the server and being redirected back to Home/Index. Seems like it defeats the point of a SPA? –  hakenmt Feb 3 at 19:49
    
That link basically suggests what I did, just under a different controller. Angular should intercept clicks and no server calls will be made when people are just using the site. Deep linking to your Angular routes, like from other websites, will hit the server though, that's why you have the catch all route in MVC. Also not every browser supports the html5 navigation mode, ex IE9, so they will hit the server every time. –  Lev D Feb 4 at 1:50

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.