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', controller: 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 。这是如何实现的?

4

7 回答 7

133
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() 中提取的路由参数"

何时(路径,路线):方法

  • path 可以包含以冒号开头并以星号结尾的命名组:例如:name*。当路由匹配时,所有字符都急切地存储在给定名称下的 $routeParams 中。
于 2014-05-22T13:14:50.363 回答
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到我的浏览器中,嘿,很快就显示了portfolio.html....

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

于 2012-12-03T11:02:25.590 回答
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();
    });
});
于 2013-05-10T06:20:52.940 回答
7

在 $routeProvider URI 模式中,您可以指定可变参数,例如:$routeProvider.when('/page/:pageNumber' ...,并通过 $routeParams 在控制器中访问它。

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

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

不幸的是,路由系统非常有限 - 关于这个主题有很多讨论,并且已经提出了一些解决方案,即通过创建多个命名视图等。但是现在,ngView 指令只为每个路由提供一个视图,on一对一的基础。你可以通过多种方式来解决这个问题——更简单的一种是使用视图的模板作为加载器,其中包含一个<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

于 2012-12-03T10:22:29.047 回答
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' 适用于任何部分姓名。

所有值都会触发动态控制器 - 所以没有“否则”但是,我认为这是您在动态或通配符路由场景中寻找的东西..

于 2013-09-28T00:17:11.433 回答
2

从 AngularJS 1.1.3 开始,您现在可以使用新的 catch-all 参数来做您想做的事。

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

从提交:

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

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

于 2013-06-28T15:57:19.277 回答
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;

    }

})();
于 2015-10-14T11:24:05.677 回答