We are investigating a migration from Backbone to Angular. Because of our design, we only need to migrate the router. I'd like to understand how wildcard routing works for angular. Here is an example of wildcard routing in Backbone:
app.Router = Backbone.Router.extend({
routes: {
'*filter' : 'setFilter'
},
setFilter: function(params) {
//all traffic ends up here. you can grab the url and go.
var url = this.cdn + "templates/" + params + ".html";
...
}
});
app.router = new app.Router();
Backbone.history.start({pushState: true});
What is the angular equivalent for wildcard routing?
How does angular handle push state? Specifically, does it have a way to utilize /pushstate urls when the browser supports pushstate and then automatically roll back to #pushstate hash urls for IE9-
Thanks.
1) There is not current support for regex in angular routing
2)Angular automatically handle pushstate if it is not available in browser then it will automatically fallback to hash mode# just use below lines
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix('!');
Related
This should be super basic but I can't get routing working. I should mention that the application is located in a subdirectory called /dist/. Here's my code:
var QuestionRouter = Backbone.Router.extend({
routes: {
"/dist/" : "startTest"
"dist/:id": "getModel"
},
startTest: function(){
console.log('home called')
},
getModel: function(){
app.getModel(id);
}
});
var app = new QuestionView;
var appRouter = new QuestionRouter;
Backbone.history.start({pushState: true});
The URL to trigger this route is:
www.example.com/dist/
www.example.com/dist/12345
Any help would be appreciated.
You'll need to use # (hash symbol).
Backbone routers are used for routing your applications URL's when
using hash tags(#)
This is a quote from a Backbone tutorial: What is a router?
See Backbone's Router documentation
Then your routes would be:
www.example.com/#/dist/
www.example.com/#/dist/12345
You can also use Backbone routes without hashes.
Ok So I was able to work this out:
My route hash should look like this:
routes: {
"" : "startTest",
":id": "getModel"
}
I had to remove pushState: true, with this in place the route wasn't being triggered, not sure why:
Backbone.history.start();
I have a sample MVC6 single page app with one view in which I want to load 2 Angular partials using ngRoute. You can have a look at it at GitHub
There are 3 URLs in the app:
localhost - Index.cshtml
localhost/games - Index.cshtml with Angular's gamelist.html partial
localhost/games/2 - Index.cshtml with Angular's game.html partial
The routes config is the following:
MVC:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}");
routes.MapRoute("gamelist", "games", new { controller = "Home", action = "Index"});
routes.MapRoute("gameWithId", "games/2", new { controller = "Home", action = "Index" });
});
Angular:
myApp.config(['$routeProvider', '$locationProvider',
function ($routeProvider, $locationProvider) {
$routeProvider
.when('/games', {
templateUrl: 'partials/gameslist.html',
controller: 'GameController',
controllerAs: 'ctrl'
})
.when('/games/:gameId', {
templateUrl: 'partials/game.html',
controller: 'GameController',
controllerAs: 'ctrl'
});
$locationProvider.html5Mode(true);
}]);
It all works perfectly fine as long as I start the app from the home page '/' and then navigate to the partials using the links on the page. The problem is that the URL #3 (localhost/games/2) does not work if I start the app from it, by typing it in the address bar. The URL #2 (/games/) does work.
The reason why #3 does not work is that MVC removes '/games' part from the URL and what Angular gets is just '/2'. If you run the sample app, you will see that '$location.path = /2'. Of course Angular cannot map using that path and no partial is rendered. So my question is - how to make MVC return the full path to the client so that Angular can map it?
You can get it to work with HTML5 mode, you just need to ensure that every request maps back to your Index.cshtml view. At that point the AngularJS framework loads, client-side routing kicks in and evaluates the request URI and loads the appropriate controller and view.
We've done this with multiple Angular apps inside MVC with different .cshtml pages, though we use attribute routing with the wildcard character, e.g.
[Route("{*anything}")]
public ActionResult Index()
{
return View("Index");
}
The wildcard operator (*) tells the routing engine that the rest of the URI should be matched to the anything parameter.
I haven't had chance to get to grips with MVC6 yet but I think you can do something like this with the "new" version of attribute routing?
[HttpGet("{*anything:regex(^(.*)?$)}"]
public ActionResult Index()
{
return View("Index");
}
To make link #3 work from the browser's address bar, I turned off "html5Mode" in Angular and made links #-based.
kudos to this blog
I think it is a better solution.
His solution is rewriting the request that doesn't fit to any route and doesn't have any extension to the landing page of angular.
Here is the code.
public class Startup
{
public void Configure(IApplicationBuilder app, IApplicationEnvironment environment)
{
// Route all unknown requests to app root
app.Use(async (context, next) =>
{
await next();
// If there's no available file and the request doesn't contain an extension, we're probably trying to access a page.
// Rewrite request to use app root
if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value))
{
context.Request.Path = "/app/index.html"; // Put your Angular root page here
await next();
}
});
// Serve wwwroot as root
app.UseFileServer();
// Serve /node_modules as a separate root (for packages that use other npm modules client side)
app.UseFileServer(new FileServerOptions()
{
// Set root of file server
FileProvider = new PhysicalFileProvider(Path.Combine(environment.ApplicationBasePath, "node_modules")),
// Only react to requests that match this path
RequestPath = "/node_modules",
// Don't expose file system
EnableDirectoryBrowsing = false
});
}
}
I am new to iron router and looking for a route equivalent of angular ui.router 'otherwise'. I was not able to find it in the documentation. What I need is, if I define the routes as:
Router.route('/', function(){
this.render('home');
});
Router.route('/signin', function(){
this.render('signin');
});
If anyone types a url other that '/' or '/signin' it should be redirected to default '/' url. Something which is done by
$urlRouterProvider.otherwise('/'); in angular.
Thanks
You have to create a route that match all routes except the defined ones.
Check this post: https://forums.meteor.com/t/how-do-i-redirect-all-non-existent-routes-in-iron-router/8556
I type url and press enter http://myservertest.com?auth=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
This one will call a service with auth param to authenticate, after authorization is successful, I want my url should be like this http://myservertest.com/mainpage without refresh app controller again.
I tried windows.location = "/" then it will refresh the page.
How can I do without refresh APP Controller ?
Just in case someone stumbles about this again after I stumbled about this after 7 years:
Usually you solve it by using $location:
$location.url('<url>');
$location.replace();
But... default html5Mode this will not replace window.location.search query parameters like
http://localhost/path?auth=xxx&andso=on
Without html5Mode (enabled:false by default) you need to care about pushState yourself before the AngularJs application runs:
Solution is to use...
window.history.replaceState(null, window.name, window.location.origin + window.location.path + window.location.hash)
(an example replacing the currently shown location url without parameters)
.. in an angular.provider() or angular.config():
In a provider when offering a reusable service:
angular.module('app').provider('AuthService', [
'someConfig',
function(someConfig){
if (someConfigObject.doItBeforeStartup) {
// ... check for parameter in window.location.search or whatever
window.history.replaceState(null, window.name, window.origin + window.path + window.hash)
}
this.readQuery = function(cfg){./* you can do it also here and call it in config*/..}
this.$get = ...
}]);
and/or in an config when using providers:
angular.module('app').config([
'AuthServiceProvider',
'someConfig',
function (AuthServiceProvider, someConfig) {
window.history.replaceState(.....)
// or in
// AuthServiceProvider.readQuery(...)
}]);
I've got a very simple setup of laravel 4 with 1 controller for trips.
Now another simple setup of Backbone with a Router and routes to regular routes like trips, trips/create. I want to use pushState: true to have nice URL but I can't seem to get it to work. When I try to reach the URLs it sends me to the page served by the server with my json data.
However, if I type: www.mysite.com/#trips I am "redirected" to www.mysite.com/trips and then my method for this specific route triggers.
Here's my Router:
App.Router = Backbone.Router.extend({
routes: {
'': 'index',
'trips': 'trips',
'trips/create': 'newTrip',
'trips/:id': 'showTrip'
},
index: function(){
},
trips: function(){
console.log('All trips') ;
},
newTrip: function(){
console.log('New trip') ;
},
showTrip: function(id){
console.log('trips id:' + id) ;
}
});
This is probably caused by the Backbone router not being able to match the URL to your Backbone routes. To debug, add this to your routes:
'*actions': 'defaultAction'
Then in the router add:
defaultAction: function(path) {
console.log('Route "' + path + '" not defined, redirecting to homepage!');
}
You will probably see that the path is different from anything in your routes. To fix this, you need to tell Backbone the root of your paths. You do this while activating pushstates.
Backbone.history.start({
pushState: true,
root: 'http://mydomain.com/myapplication/'
});
Hope this helps.