Matthew Rhoden Matthew Rhoden - 3 months ago 17
AngularJS Question

Can ngRoute support non-configured links?

I am trying to fix up an existing implementation, however I can't do it all at once. Is there anyway I can get ngRoute, even if it's a hack, to support old links that expect to make a direct request?

Here's what I mean, we have three links in this weird example TODO App:

<a href="/Home">Home</a>
<a href="/Home/AddItem">New Task</a>
<a href="/Home/Complete">Complete Task</a>


"Home" and "New Task" should use the angular ngRoute, making it nice and snappy. My other links, such as "Complete" would need to work like they always have, the full round trip.

Initially I configured ngRoute with this:

angular.module('TodoApp', [
// Angular modules
'ngRoute'
// Custom modules

// 3rd Party Modules
]).config(['$locationProvider', '$routeProvider',
function config($locationProvider, $routeProvider) {
$routeProvider.when('/', {
templateUrl: 'Templates/index.html',
controller: 'TodoController'
})
.when('/Home/AddItem', {
templateUrl: 'Templates/AddItem.html',
controller: 'AddItemController'
});
// Otherwise, continue to the link like normal.
$locationProvider.html5Mode(true);
}
]);


However that won't work, so far, here's the full list of options that I've tried:

Don't configure otherwise

This only gave me a blank page as ngRoute is blocking the browser from making an http request.

Hide/Show view div

I've tried configuring the router to hide or show the divs based on what url is being rendered, this almost works. I can go to a bookmarked page and it will render, but I can't navigate through the website via clicking an link. I get the same blank page because ngRoute blocked it again.

Configure otherwise

I tried a "NoView" controller, doesn't work. Also found that if I put this code in

redirectTo: function() {
return undefined;
}


I can get it to at least render without errors, but again ngRoute blocks the browser from making an http request.

Disable ngRoute

I tried detecting when the configured path is being used, only then would I enable angular. While there are errors in the console at least it works for bookmarked links. Again though, once it becomes enabled ngRoute will start blocking links while clicking around the site. You'll start to see blank pages instead.

I would try the alternative angular-ui-route, but I don't know if it supports this case. Routing seems to be all or nothing. Are there any hacks to get around this or another framework that supports this case?

There's a lot of links so I would like to leave them alone and only enable new features until we can go back and fix up the old ones.

Final Approach

Adding for those who are curious, I ended up merging one of my attempts with Horst Jahns answer. Basically it looks like this:

var angularConfigs = [
// Set all configs here, routing will be conditionally added later.
// Angular modules

// Custom modules

// 3rd Party Modules
];

var routeSettings = [{
entry: '/',
template: 'Templates/index.html',
controller: 'TodoController'
}, {
entry: '/Home/AddItem',
template: 'Templates/AddItem.html',
controller: 'AddItemController'
}
];

// Check current url matches routes being registered. If so enable routing.
var enableRotues = false;
for (var i = 0; i < routeSettings.length; i++) {
if (routeSettings[i].entry === window.location.pathname) {
enableRotues = true;
break;
}
}

if (enableRotues) {
// Attach the module to existing configurations.
angularConfigs.push('ngRoute');
var todoApp = angular.module('TodoApp', angularConfigs);

todoApp.config([
'$locationProvider', '$routeProvider',
function config($locationProvider, $routeProvider) {
var provider = $routeProvider;

// Go through each setting and configure the route provider.
for (var i = 0; i < routeSettings.length; i++) {
var route = routeSettings[i];

provider = provider.when(route.entry,
{
templateUrl: route.template,
controller: route.controller
});
}

// This enables links without hashes, gracefully degrades.
$locationProvider.html5Mode(true);
}
]);

// This directive will disable routing on all links NOT
// marked with 'data-routing-enabled="true"'.
todoApp.directive('a', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
if (attrs.routingEnabled) {
// Utilize the ngRoute framework.
} else {
// Disable ngRoute so pages continue to load like normal.
element.bind('click', function(event) {
if (!scope.enabled) {
event.preventDefault();
window.location.href = attrs.href;
}
});
}
}
};
});
} else {
// In this case we still want angular to properly be stood
// up and register controllers in my case for backward
// compatibility.
angular.module('TodoApp', angularConfigs);
}

Answer

You could write a directive and set it on all the links, which are not configured.

Angular

app.directive('nonConfig', function() {
 return {
     restrict: 'A',
     link: function(scope, element, attrs) {
         element.bind('click', function(event) {
             if(!scope.enabled) {
                 event.preventDefault();
                 window.location.href = attrs.href;
             }
         });
     }
 };
});

HTML

<a href="test.html" data-non-config>test</a>
Comments