AngularJS 动态路由

IT技术 javascript angularjs content-management-system url-routing
2021-01-22 05:16:26

我目前有一个内置路由的 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 文件到/pages目录中。

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

在理想的世界中,路由模式将是:

$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这是如何实现的?

6个回答
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/sales/list将被这个提供者捕获

从文档(1.3.0):

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

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

当(路径,路线):方法

  • 路径可以包含以冒号开头并以星号结尾的命名组:例如:name*。当路由匹配时,所有字符都急切地存储在给定名称下的 $routeParams 中。
需要与时俱进……我构建的在 v1.0.2 中缺失的功能现在可用。更新已接受的答案
2021-03-19 05:16:26
老实说,我从来没有在当前的 1.3 测试版中使用过这个
2021-03-22 05:16:26
请解释,从哪里urlattr设置或发送,我的意思是urlattr.name会产生什么?
2021-03-30 05:16:26
当我这样做时,它实际上开始工作了... when('/:page', { templateUrl : function(parameters) { return parameters.page + '.html'; }
2021-04-01 05:16:26
说真的.. Angular 没有将它作为默认行为真的很愚蠢......手动路由是荒谬的
2021-04-06 05:16:26

好的解决了。

将解决方案添加到 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 并将其命名为投资组合.html,更改了其中的一些内容并输入/#/pages/portfolio到我的浏览器中,然后显示了 presto 投资组合.html....

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

如果我理解正确,这仅适用于静态内容。这是因为在通过 jQuery(在 angular 的范围之外)实例化控制器之后,您正在更改 DOM。像 {{this}} 这样的变量可能会起作用(我必须尝试一下),但指令很可能不会。小心这一点,因为它现在可能有用,但以后可能会破坏代码..
2021-03-17 05:16:26
不 - ng-view 指令相当有限 - 或者更好地说,它专门用于本地路由系统(反过来,仍然有限,恕我直言)。你可以按照你说的做,将内容注入到一个 DOM 元素中,然后调用 $compile 方法,告诉 angular 重新读取结构。这将触发任何需要完成的绑定。
2021-03-23 05:16:26
有效,但您不应在控制器中进行 DOM 操作。
2021-03-30 05:16:26
确实,绑定对我来说不起作用,但是我并不太大惊小怪,因为我只希望客户能够添加新页面。我添加的任何页面我都会通过路由配置适当地指定。不过好点。
2021-04-04 05:16:26
如果您想呈现静态 html 内容,这不是一个糟糕的解决方案。只要您记住,您实际上是在用静态(非角度)内容覆盖 ng-view。考虑到这一点,将两者分开会更清晰,创建类似 <div id="user-views"></div> 元素的内容,并在那里注入您的“用户模板”。此外,覆盖 $route.current.templateUrl 绝对没有意义 - 创建 $scope.userTemplate 模型并执行 $('#user-views").load($scope.userTemplate) 更干净,并且不会破坏任何角度代码。
2021-04-09 05:16:26

我认为最简单的方法是稍后解析路由,例如,您可以通过 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();
    });
});
@virtualandy,这通常不是一个好方法,因为您要在不同阶段提供提供者——这反过来可能会泄漏应该在配置阶段隐藏的高级实用程序。我的建议是使用UI-Router(解决了很多困难),使用“resolve”、“controllerAs”以及其他功能,例如将templateUrl设置为函数。我还构建了一个我可以共享的“presolve”module,它可以对路由方案的任何部分(模板、templateUrl、控制器等)进行 $interpolate。上面的解决方案是一个更优雅的解决方案——但是您主要关注什么?
2021-03-14 05:16:26
@Cody 你能解释一下安全/应用程序内聚说明吗?我们在一条类似的船上,类似上面的答案会非常方便。
2021-03-22 05:16:26
$routeProvider用作 a 的别名factory(在 之后可用config)不会在安全性和应用程序凝聚力方面发挥良好作用 - 无论哪种方式,都很酷的技术(upvote!)。
2021-03-25 05:16:26
@virtualandy,这是一个用于lazyLoaded 模板、控制器等的module——很抱歉它不在repo 中,但这里有一个小提琴:jsfiddle.net/cCarlson/zdm6gpnb ...这个lazyLoads 以上——并且——可以插入任何东西基于 URL 参数。该module可以使用一些工作,但它至少是一个起点。
2021-03-28 05:16:26
@Cody - 没问题,感谢提供样本和进一步解释。有道理。在我们的例子中,我们使用了angular-route-segment并且效果很好。但是我们现在需要支持“动态”路由(一些部署可能没有页面的完整功能/路由,或者可能会更改它们的名称等)并且我们的想法是在一些 JSON 中加载定义路由的实际实现之前但显然在 .config() 中使用 $http/$providers 时遇到了问题。
2021-04-03 05:16:26

在 $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 更好的方法。
2021-03-15 05:16:26

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

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

无需在 ng-view 中进行任何调整。'/:a' 情况是我发现的唯一可以实现这一点的变量.. '/:foo' 不起作用,除非你的局部变量都是 foo1、foo2 等......'/:a' 适用于任何局部变量名称。

所有值都会触发动态控制器 - 所以没有“其他”,但是,我认为这是您在动态或通配符路由方案中寻找的。