Javascript AngularJS 动态路由
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13681116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AngularJS dynamic routing
提问by Greg
I currently have an AngularJS application with routing built in. It works and everything is ok.
我目前有一个内置路由的 AngularJS 应用程序。它工作正常,一切正常。
My app.js file looks like this:
我的 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: '/' });
}]);
My app has a CMS built in where you can copy and add new html files within the /pagesdirectory.
我的应用程序内置了一个 CMS,您可以在其中复制和添加新的 html 文件到/pages目录中。
I would like to still go through the routing provider though even for the new dynamically added files.
即使对于新的动态添加的文件,我仍然希望通过路由提供程序。
In an ideal world the routing pattern would be:
在理想的世界中,路由模式将是:
$routeProvider.when('/pagename', { templateUrl: '/pages/pagename.html', controller: CMSController });
$routeProvider.when('/ pagename', { templateUrl: '/pages/ pagename.html', controller: CMSController });
So if my new page name was "contact.html" I would like angular to pick up "/contact" and redirect to "/pages/contact.html".
因此,如果我的新页面名称是“contact.html”,我希望 angular 选择“/contact”并重定向到“/pages/contact.html”。
Is this even possible?! and if so how?!
这甚至可能吗?!如果是这样怎么办?!
Update
更新
I now have this in my routing config:
我现在在我的路由配置中有这个:
$routeProvider.when('/page/:name', { templateUrl: '/pages/home.html', controller: CMSController })
and in my CMSController:
在我的 CMSController 中:
function CMSController($scope, $route, $routeParams) {
$route.current.templateUrl = '/pages/' + $routeParams.name + ".html";
alert($route.current.templateUrl);
}
CMSController.$inject = ['$scope', '$route', '$routeParams'];
This sets the current templateUrl to the right value.
这会将当前 templateUrl 设置为正确的值。
HoweverI would now like to change the ng-viewwith the new templateUrl value. How is this accomplished?
但是,我现在想使用新的 templateUrl 值更改ng-view。这是如何实现的?
回答by Robin Rizvi
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 directoriesdynamically. Example: /page/cars/selling/listwill be catch on this provider
- 添加 * 可让您动态处理多级目录。示例:/page/cars/sales/list将被此提供程序捕获
From the docs (1.3.0):
从文档(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"
“如果 templateUrl 是一个函数,它将使用以下参数调用:
{Array.} - 通过应用当前路由从当前 $location.path() 中提取的路由参数"
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.
当(路径,路线):方法
- 路径可以包含以冒号开头并以星号结尾的命名组:例如:name*。当路由匹配时,所有字符都急切地存储在给定名称下的 $routeParams 中。
回答by Greg
Ok solved it.
好的解决了它。
Added the solution to GitHub- http://gregorypratt.github.com/AngularDynamicRouting
将解决方案添加到 GitHub- http://gregorypratt.github.com/AngularDynamicRouting
In my app.js routing config:
在我的 app.js 路由配置中:
$routeProvider.when('/pages/:name', {
templateUrl: '/pages/home.html',
controller: CMSController
});
Then in my CMS controller:
然后在我的 CMS 控制器中:
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>
#views 是我的 <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/portfoliointo my browser and hey presto portfolio.html was displayed....
为了测试它,我复制了 about.html 并将其命名为投资组合.html,更改了其中的一些内容并输入/#/pages/portfolio到我的浏览器中,嘿,显示了投资组合.html....
UpdatedAdded $apply and $compile to the html so that dynamic content can be injected.
更新 将$apply 和 $compile 添加到 html 以便可以注入动态内容。
回答by eazel7
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.
我认为最简单的方法是稍后解析路由,例如,您可以通过 json 询问路由。查看我在配置阶段通过 $provide 使用 $routeProvider 创建了一个工厂,因此我可以在运行阶段甚至在控制器中继续使用 $routeProvider 对象。
'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();
});
});
回答by Tiago Rold?o
In the $routeProvider URI patters, you can specify variable parameters, like so: $routeProvider.when('/page/:pageNumber' ..., and access it in your controller via $routeParams.
在 $routeProvider URI 模式中,您可以指定可变参数,例如: $routeProvider.when('/page/:pageNumber' ...,并通过 $routeParams 在您的控制器中访问它。
There is a good example at the end of the $route page: http://docs.angularjs.org/api/ng.$route
$route 页面末尾有一个很好的例子: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).
不幸的是,路由系统非常有限 - 关于这个主题有很多讨论,并且已经提出了一些解决方案,即通过创建多个命名视图等。但是现在,ngView 指令只为每个路由提供一个视图,在一对一的基础。您可以通过多种方式解决此问题 - 更简单的方法是使用视图的模板作为加载器,其中包含一个<ng-include src="myTemplateUrl"></ng-include>标签($scope.myTemplateUrl 将在控制器中创建)。
I use a more complex (but cleaner, for larger and more complicated problems) solution, basically skipping the $route service altogether, that is detailed here:
我使用了一个更复杂(但更清晰,用于更大更复杂的问题)的解决方案,基本上完全跳过 $route 服务,这里有详细说明:
回答by Matthew Luchak
Not sure why this works but dynamic (or wildcard if you prefer) routes are possible in angular 1.2.0-rc.2...
不确定为什么会这样,但是在 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/foo -> 加载“foo”部分
example.com/bar-> loads "bar" partial
example.com/bar-> 加载“bar”部分
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.
无需在 ng-view 中进行任何调整。'/:a' case 是我发现的唯一可以实现这一点的变量.. '/:foo' 不起作用,除非你的局部变量都是 foo1、foo2 等......'/:a' 适用于任何局部变量姓名。
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..
所有值都会触发动态控制器 - 所以没有“其他”,但是,我认为这是您在动态或通配符路由方案中寻找的。
回答by Dave
As of AngularJS 1.1.3, you can now do exactly what you want using the new catch-all parameter.
从 AngularJS 1.1.3 开始,您现在可以使用新的 catch-all 参数做您想做的事情。
https://github.com/angular/angular.js/commit/7eafbb98c64c0dc079d7d3ec589f1270b7f6fea5
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/*largecodewill match with something like thishttp://appdomain.com/edit/color/brown/largecode/code/with/slashs.
这允许 routeProvider 接受匹配子字符串的参数,即使它们包含斜杠,如果它们以星号而不是冒号为前缀。例如,路由 like
edit/color/:color/largecode/*largecode将匹配这样的东西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.
我自己测试过(使用 1.1.5)并且效果很好。请记住,每个新 URL 都会重新加载您的控制器,因此要保持任何类型的状态,您可能需要使用自定义服务。
回答by kevinius
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;
}
})();

