AngularJS动态路由


88

我目前有一个内置路由的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,您可以在其中复制和添加/ pages目录中的新html文件。

即使对于新动态添加的文件,我仍然希望通过路由提供程序。

在理想的情况下,路由模式为:

$ routeProvider.when('/ pagename ',{templateUrl:'/ pages / pagename .html',控制器:CMSController});

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

这有可能吗?如果是这样怎么办?

更新资料

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

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

在我的CMSController中:

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

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

但是,我现在想用新的templateUrl值更改ng-view。这是如何完成的?

Answers:


132
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'
        });
    }
]);
  • 添加*使您可以动态处理多个级别的目录。例如:/ page / cars / selling / list将被该提供程序捕获

从文档(1.3.0):

“如果templateUrl是一个函数,则将使用以下参数调用它:

{Array。}-通过应用当前路线从当前$ location.path()中提取的路线参数”

when(path,route):方法

  • path可以包含以冒号开头并以星号结尾的命名组:例如:name *。当路由匹配时,所有字符都以给定名称急切地存储在$ routeParams中。

5
需要与时俱进... v1.0.2中缺少的我构建的功能现在可用。更新对此答案的公认答案
Greg 2014年

老实说,我从来没有使用当前的1.3 Beta来工作
Archimedes Trajano 2014年

当我执行此操作时,实际上就可以正常工作了……when('/:page',{templateUrl:function(parameters){return parameters.page +'.html';}
Archimedes Trajano 2014年

严重.. Angular没有默认行为是非常愚蠢的...手动路由是荒谬的
Guilherme Ferreira 2015年

3
请说明,urlattr是从哪里设置或发送的,我的意思是urlattr.name会产生什么?
萨米

37

好,解决了。

将解决方案添加到GitHub - http://gregorypratt.github.com/AngularDynamicRouting

在我的app.js路由配置中:

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

然后在我的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'];

#views是我的 <div id="views" ng-view></div>

因此,现在它可以与标准路由和动态路由一起使用。

为了测试它,我复制了about.html文件,称为Portfolio.html,更改了其中的一些内容并输入/#/pages/portfolio到浏览器中,然后显示了presto Portfolio.html。

更新将 $ apply和$ compile添加到html,以便可以注入动态内容。


2
如果我正确理解,这仅适用于静态内容。这是因为在实例化控制器之后,您正在通过jQuery(超出angular的范围)来更改DOM。像{{this}}这样的变量可能会起作用(我必须尝试一下),但指令很可能不会起作用。警惕这一点,因为它可能现在是有用的,但后来能打破代码..
蒂亚戈Roldão

是的,绑定是行不通的,但是对我而言,我并不太着急,因为我只希望客户端能够添加新页面。我添加的任何页面都可以通过route config适当地指定。好点。
格雷格2012年

1
如果要呈现静态html内容,这不是一个不好的解决方案。只要您牢记,本质上就是使用静态(非角度)内容覆盖ng视图。考虑到这一点,将两者分开,创建类似于<div id =“ user-views”> </ div>的元素,然后在其中注入“用户模板”会更加干净。另外,重写$ route.current.templateUrl绝对没有意义-创建$ scope.userTemplate模型并执行$('#user-views“)。load($ scope.userTemplate)会更干净,并且不会破坏angular的代码
TiagoRoldão2012年

1
不-ng-view指令相当有限-或更好地说,它专门用于本机路由系统(反过来,仍然有限,恕我直言)。您可以按照您说的做,将内容注入DOM元素,然后调用$ compile方法,以告知angular重新读取该结构。这将触发任何需要完成的绑定。
TiagoRoldão2012年

2
可以,但是您不应该在控制器中进行DOM操作。
dmackerman 2013年

16

我认为最简单的方法是稍后解析路由,例如,您可以通过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();
    });
});

$routeProvider用作别名factory(在之后可用config)在安全性和应用程序凝聚力方面不能很好地发挥作用-无论哪种方式,很酷的技术(赞成!)。
科迪2014年

@Cody您能解释一下安全性/应用程序衔接说明吗?我们在类似的船上,上面的答案很方便。
virtualandy 2014年

2
@virtualandy,通常这不是一个好方法,因为您要在不同阶段提供提供程序,这反过来又会泄漏应隐藏在配置阶段的高级实用程序。我的建议是使用UI-Router(解决很多困难),使用“ resolve”,“ controllerAs”和其他功能,例如将templateUrl设置为函数。我还构建了一个我可以共享的“预解决”模块,可以对路由方案的任何部分(模板,templateUrl,控制器等)进行内插。上面的解决方案是一种更优雅的解决方案-但是您主要关注什么?
科迪2014年

1
@virtualandy,这是用于lazyLoaded模板,控制器等的模块-抱歉,它不在仓库中,但这里有一个小提琴: 仓库中 jsfiddle.net/cCarlson/zdm6gpnb ...基于URL参数。该模块可能需要一些工作,但至少是一个起点。
科迪

@Cody-没问题,感谢您的示例和进一步的解释。说得通。在我们的例子中,我们使用了angular-route-segment,并且效果很好。但是我们现在需要支持“动态”路由(某些部署可能没有页面的完整功能/路由,或者可能更改其名称,等等),而在实际实现之前在定义路由的JSON中加载的概念就是我们的想法但是显然在.config()中使用$ http / $ providers遇到了问题。
virtualandy 2014年

7

在$ routeProvider URI模式中,您可以指定变量参数,如下所示: $routeProvider.when('/page/:pageNumber' ...,然后通过$ routeParams在控制器中对其进行访问。

$ route页面末尾有一个很好的例子:http : //docs.angularjs.org/api/ng.$ro​​ute

编辑(针对已编辑的问题):

不幸的是,路由系统非常有限-有关此主题的讨论很多,并且已经提出了一些解决方案,例如,通过创建多个命名视图等。但是现在,ngView指令在每个路由上仅提供一个视图,一对一的基础。您可以通过多种方式进行操作-更简单的方法是将视图的模板用作加载器,并<ng-include src="myTemplateUrl"></ng-include>在其中带有标签(将在控制器中创建$ scope.myTemplateUrl)。

我使用了一个更复杂的解决方案(但是对于更大型和更复杂的问题更清洁),基本上完全跳过了$ route服务,在这里进行详细介绍:

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


我喜欢这种ng-include方法。它非常简单,并且比操作DOM更好。
Neel 2014年

5

不确定为什么这样做,但是在角度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->局部加载“ foo”

example.com/bar->局部加载“ bar”

无需在ng-view中进行任何调整。'/:a'是我发现的唯一可以实现此目的的变量。.'/:foo'无效,除非您的部分都是foo1,foo2等...'/:a'可以与任何部分一起使用名称。

所有值都会触发动态控制器-因此没有“否则”的情况,但是,我认为这是您在动态或通配符路由方案中要寻找的。


2

从AngularJS 1.1.3开始,您现在可以使用新的catch-all参数完全执行所需的操作。

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

从提交:

这允许routeProvider接受与子字符串匹配的参数,即使它们包含斜杠(即使它们以星号而不是冒号作为前缀)也是如此。例如,类似的路线edit/color/:color/largecode/*largecode 将与此类似 http://appdomain.com/edit/color/brown/largecode/code/with/slashs

我自己(使用1.1.5)对其进行了测试,并且效果很好。请记住,每个新URL都会重新加载您的控制器,因此,要保持任何状态,您可能需要使用自定义服务。


0

这是另一个行之有效的解决方案。

(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;

    }

})();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.