MVC and AngularJS Single Page Application - angularjs

I have an MVC Razor app that I have just converted to a Single Page Application using AngularJS and Angular UI Router.
I have a problem in that when I go to a URL (via a refresh) such as /settings/options MVC attempts to look for the Options() method on the Settings controller. Once the page has finished loading the Angular routing takes over and shows the correct page.
Because my layout page HAS to have a RenderBody() call (else an exception is thrown) I end up with my page looking correct but having a 404 page at the bottom. The 404 is rendered into RenderBody because it cannot find the Options() method on the Settings controller
How can I fix this? I presume using some kind of MVC Routing but not sure where to start. Here is my current route
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
This question has a similar problem except they use WebAPI and I have my endpoints within a normal controller. If I use the solution here all my AJAX requests get redirected too

I feel like this question (How to use ASP.NET MVC and AngularJS routing?) might help you. They're using different "Areas" of the site, but it's the same concept for the routing.
You could also look into the URL Rewriter for IIS config and use that to make rules to always route your SPA requests to the angular app...
How do I configure IIS for URL Rewriting an AngularJS application in HTML5 mode?

Related

Asp.net MVC Routes With Angular

I have an angular application (backed by .Net 4.6 and MVC5) with routes such as
/admin
/admin/manageusers
/admin/export
I can reach these via client side routing if my asp.net application sends me to /Admin.
However, if I refresh the page the MVC routing engine doesn't know where to send me and I end up with a 404.
I've tried as many variations of this as I can think of with no success.
context.MapRoute(
"Admin_root",
"Admin/{*url}",
new { area = "Admin", controller = "Admin", action = "Index" });
Is there a way to tell MVC to ignore what would traditionally be the controller and action and just continue with the Index action?
Is there a way to build a catch all route that will ignore what would typically be the controller and action?
The ASP.NET Core Angular project template includes a call to MapSpaFallbackRoute for exactly this purpose. You can see a detailed explanation of this in Github.
Here's the code example:
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
Here's part of the explanation:
Then, since MapSpaFallbackRoute is last, any other requests that don't appear to be for static files will be served by invoking the Index action on HomeController. This action's view should serve your client-side application code, allowing the client-side routing system to handle whatever URL has been requested.
You'll need a reference to Microsoft.AspNetCore.SpaServices if you don't already have it.
EDIT: Since you've specified that you're not using ASP.NET Core, take a look at this asnwer: How to use ASP.NET MVC and AngularJS routing?. It's a similar approach to what I described but for ASP.NET MVC 5. The solution suggested there does seem to basically be the same as what you've described, however.

How can Laravel ignore everything except certain prefix?

I have my angular app running off of my laravel route /
I have everything else under /api.
I want to be able to enable html5 mode in angular and maintain SPA like routing, but when I do, laravel catches the route.
So how can I get laravel router to ignore everything except api and the initial route?
using laravel 5.2
I think you can do the following:
// Catch any routes except 'api'
Route::any('{all}', 'InitController#index')->where('all','^((?!api).)*?');
You will need to have a catch-all route to render index view on every request - then let Angular handle routing. Remember, you will also need to create 404 pages etc within Angular app.
// API routes here
// Catch-all route to point everything to index page
Route::get('{something}', function() {
return view('index');
});
With regards to the API routes, you need to place these above your catch-all route so that they return an API response.
Angular Routing
Are you using Angular 1 or 2? What angular router are you using? e.g. with Angular1 using $location you add false as 2nd parameter to path:
$location.path('/some-path/', false);

AngularJS with MVC 6

This is an MVC 6/WebApi application. I'm attempting to use WebApi on the backend with AngularJS on the frontend.
I have two static files: index.html and login.html
(There will eventually be more static files.)
My Angular app is contained in the index.html while views (such as /login) are loaded from static files (i.e. login.html).
If I go to my root URL, index.html is loaded just fine. However, if I go to /login, I receive a 404 page not found.
Now, let it be said, I DO NOT want to bog down my application with a bunch of controllers and views as it's unnecessary to simply serve static files. That's overkill.
I have my routes setup to serve API calls (i.e. ~/api/whatever). How I get MVC 6 to ignore all other routes?
FYI, it also appears that MapPageRoute is deprecated in MVC 6?
EDIT:
One thing I've done to actually get it working is add my own middleware to intercept the request. The code below is added after all of my default middleware in the Configure method:
app.Use(next => async context =>
{
if (context.Request.Path.Value.StartsWith("/api"))
await next.Invoke(context);
else
await context.Response.WriteAsync(System.IO.File.ReadAllText("index.html"));
});
This seems a bit much and it's just a hack. All it does is allows any request that begins with "/api" to go through (which is then picked up by the MVC middleware), but any other call is served with the contents of the index.html. So, if my requested URL is "/login", the index.html file is served, then Angular looks at the route and loads the login.html file into view.
Any other suggestions?
Okay, so since something didn't exist in the MVC 6/ASP.NET 5 framework, I've created my own middleware that provides a lot more flexibility. It has been added to GitHub and is available through NuGet.
The project page is: https://github.com/a11smiles/AngularMiddleware
I was able do what you are asking here. Basically, I added a catch all route to my index action:
[Route("{*path}")]
meaning if no MVC action does not exist, call my Index action and angular routing will take from there

expressjs static content and angular app

I am trying to load a yeoman angular app only once the user hits a specific page inside of express (e.g. '/dashboad').
The end goal is to have multiple static front pages on express without using angular. Then I would use the angular routes/ application once a user has logged in.
I have successfully followed Yeoman inside ExpressJS
but this boots up angular right from the start and does not allow routing to any express html pages.
We already chatted about this in person, but the answer here is to not have your Angular app be the base route in Express. You would have separate routes in Express for each of the static pages and finally one route for the Angular page. For example:
/ => /index.html
/dashboard/ => /dashboard.html (this is the Angular app)
/faq/ => faq.html
As long as the Angular app script is not loaded outside the one Angular route, everything will work as you expect.

How to serve page with Backbone Controller

Backbone define routes in its Controller in the following fashion. Does this mean every page of the site must have a copy of it? Or that every script must be load when the user reach the first page to make it work?
var Workspace = Backbone.Controller.extend({
routes: {
"help": "help", // #help
"search/:query": "search", // #search/kiwis
"search/:query/p:page": "search" // #search/kiwis/p7
},
help: function() {
...
},
search: function(query, page) {
...
}
});
It's a hashbang router, those's aren't real pages. The urls look like:
mysite/!#help
mysite/!#search/kiwis
etc.
It's used to route single page web apps. So you only serve one page and then render other pages by getting your data from a JSON web service.
Backbone.js allows you to route to sub pages on the client inside a page. This means you can change your URL to a book markable state and when you reload the page, backbone will reload that "section" of the page.
This routing should only be used inside a page and should not span across multiple pages.
You should be using your serverside MVC framework for that.
CodeIgniter for PHP
Express for node.js
Rails for Ruby/Groovy
MVC for ASP.NET
Django for Python
etc.

Resources