动态路由

我目前有一个 AngularJS 应用程序与路由内置。 它工作,一切都很好。

我的 app.js 文件如下:

angular.module('myapp', ['myapp.filters', 'myapp.services', 'myapp.directives']).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', { templateUrl: '/pages/home.html', controller: HomeController });
$routeProvider.when('/about', { templateUrl: '/pages/about.html', controller: AboutController });
$routeProvider.when('/privacy', { templateUrl: '/pages/privacy.html', controller: AboutController });
$routeProvider.when('/terms', { templateUrl: '/pages/terms.html', controller: AboutController });
$routeProvider.otherwise({ redirectTo: '/' });
}]);

我的应用程序有一个内置的 CMS,在那里你可以复制和添加新的 html 文件在 /页目录。

我想仍然通过路由提供程序,即使是新的动态添加的文件。

在理想情况下,路由模式应该是:

$routeProvider.when (’/页名’,{ templateUrl:’/pages/页名.html’,controller: CMSController }) ;

因此,如果我的新页面名称是“ contact.html”,我希望能够选择“/contact”并重定向到“/pages/contact.html”。

这可能吗,如果可能,怎么可能!

更新

我现在在我的路由配置中有这个:

$routeProvider.when('/page/:name', { templateUrl: '/pages/home.html', controller: CMSController })

在我的 CMS 控制器中:

function CMSController($scope, $route, $routeParams) {
$route.current.templateUrl = '/pages/' + $routeParams.name + ".html";
alert($route.current.templateUrl);
}
CMSController.$inject = ['$scope', '$route', '$routeParams'];

这将当前 templateUrl 设置为正确的值。

但是 我现在想用新的 templateUrl 值更改 美景

159042 次浏览

In the $routeProvider URI patters, you can specify variable parameters, like so: $routeProvider.when('/page/:pageNumber' ... , and access it in your controller via $routeParams.

There is a good example at the end of the $route page: http://docs.angularjs.org/api/ng.$route

EDIT (for the edited question):

The routing system is unfortunately very limited - there is a lot of discussion on this topic, and some solutions have been proposed, namely via creating multiple named views, etc.. But right now, the ngView directive serves only ONE view per route, on a one-to-one basis. You can go about this in multiple ways - the simpler one would be to use the view's template as a loader, with a <ng-include src="myTemplateUrl"></ng-include> tag in it ($scope.myTemplateUrl would be created in the controller).

I use a more complex (but cleaner, for larger and more complicated problems) solution, basically skipping the $route service altogether, that is detailed here:

http://www.bennadel.com/blog/2420-Mapping-AngularJS-Routes-Onto-URL-Parameters-And-Client-Side-Events.htm

Ok solved it.

Added the solution to GitHub - http://gregorypratt.github.com/AngularDynamicRouting

In my app.js routing config:

$routeProvider.when('/pages/:name', {
templateUrl: '/pages/home.html',
controller: CMSController
});

Then in my CMS controller:

function CMSController($scope, $route, $routeParams) {


$route.current.templateUrl = '/pages/' + $routeParams.name + ".html";


$.get($route.current.templateUrl, function (data) {
$scope.$apply(function () {
$('#views').html($compile(data)($scope));
});
});
...
}
CMSController.$inject = ['$scope', '$route', '$routeParams'];

With #views being my <div id="views" ng-view></div>

So now it works with standard routing and dynamic routing.

To test it I copied about.html called it portfolio.html, changed some of it's contents and entered /#/pages/portfolio into my browser and hey presto portfolio.html was displayed....

Updated Added $apply and $compile to the html so that dynamic content can be injected.

I think the easiest way to do such thing is to resolve the routes later, you could ask the routes via json, for example. Check out that I make a factory out of the $routeProvider during config phase, via $provide, so I can keep using the $routeProvider object in the run phase, and even in controllers.

'use strict';


angular.module('myapp', []).config(function($provide, $routeProvider) {
$provide.factory('$routeProvider', function () {
return $routeProvider;
});
}).run(function($routeProvider, $http) {
$routeProvider.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
}).otherwise({
redirectTo: '/'
});


$http.get('/dynamic-routes.json').success(function(data) {
$routeProvider.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
});
// you might need to call $route.reload() if the route changed
$route.reload();
});
});

As of AngularJS 1.1.3, you can now do exactly what you want using the new catch-all parameter.

https://github.com/angular/angular.js/commit/7eafbb98c64c0dc079d7d3ec589f1270b7f6fea5

From the commit:

This allows routeProvider to accept parameters that matches substrings even when they contain slashes if they are prefixed with an asterisk instead of a colon. For example, routes like edit/color/:color/largecode/*largecode will match with something like this http://appdomain.com/edit/color/brown/largecode/code/with/slashs.

I have tested it out myself (using 1.1.5) and it works great. Just keep in mind that each new URL will reload your controller, so to keep any kind of state, you may need to use a custom service.

Not sure why this works but dynamic (or wildcard if you prefer) routes are possible in angular 1.2.0-rc.2...

http://code.angularjs.org/1.2.0-rc.2/angular.min.js
http://code.angularjs.org/1.2.0-rc.2/angular-route.min.js


angular.module('yadda', [
'ngRoute'
]).


config(function ($routeProvider, $locationProvider) {
$routeProvider.
when('/:a', {
template: '<div ng-include="templateUrl">Loading...</div>',
controller: 'DynamicController'
}).




controller('DynamicController', function ($scope, $routeParams) {
console.log($routeParams);
$scope.templateUrl = 'partials/' + $routeParams.a;
}).

example.com/foo -> loads "foo" partial

example.com/bar-> loads "bar" partial

No need for any adjustments in the ng-view. The '/:a' case is the only variable I have found that will acheive this.. '/:foo' does not work unless your partials are all foo1, foo2, etc... '/:a' works with any partial name.

All values fire the dynamic controller - so there is no "otherwise" but, I think it is what you're looking for in a dynamic or wildcard routing scenario..

angular.module('myapp', ['myapp.filters', 'myapp.services', 'myapp.directives']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/page/:name*', {
templateUrl: function(urlattr){
return '/pages/' + urlattr.name + '.html';
},
controller: 'CMSController'
});
}
]);
  • Adding * let you work with multiple levels of directories dynamically. Example: /page/cars/selling/list will be catch on this provider

From the docs (1.3.0):

"If templateUrl is a function, it will be called with the following parameters:

{Array.} - route parameters extracted from the current $location.path() by applying the current route"

Also

when(path, route) : Method

  • path can contain named groups starting with a colon and ending with a star: e.g.:name*. All characters are eagerly stored in $routeParams under the given name when the route matches.

Here is another solution that works good.

(function() {
'use strict';


angular.module('cms').config(route);
route.$inject = ['$routeProvider'];


function route($routeProvider) {


$routeProvider
.when('/:section', {
templateUrl: buildPath
})
.when('/:section/:page', {
templateUrl: buildPath
})
.when('/:section/:page/:task', {
templateUrl: buildPath
});






}


function buildPath(path) {


var layout = 'layout';


angular.forEach(path, function(value) {


value = value.charAt(0).toUpperCase() + value.substring(1);
layout += value;


});


layout += '.tpl';


return 'client/app/layouts/' + layout;


}


})();