简体   繁体   English

AngularJS动态路由

[英]AngularJS dynamic routing

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 /pages directory. 我的应用程序内置了CMS,您可以在其中复制和添加/ pages目录中的新html文件。

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',控制器: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设置为正确的值。

However I would now like to change the ng-view with the new templateUrl value. 但是,我现在想用新的templateUrl值更改ng-view How is this accomplished? 这是如何完成的?

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 例如: / page / cars / selling / list将被该提供程序捕获

From the docs (1.3.0): 从文档(1.3.0):

"If templateUrl is a function, it will be called with the following parameters: “如果templateUrl是一个函数,则将使用以下参数调用它:

{Array.} - route parameters extracted from the current $location.path() by applying the current route" {Array。}-通过应用当前路线从当前$ location.path()中提取的路线参数”

Also

when(path, route) : Method when(path,route):方法

  • path can contain named groups starting with a colon and ending with a star: eg:name*. path可以包含以冒号开头并以星号结尾的命名组:例如:name *。 All characters are eagerly stored in $routeParams under the given name when the route matches. 当路由匹配时,所有字符都以给定名称急切地存储在$ routeParams中。

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/portfolio into my browser and hey presto portfolio.html was displayed.... 为了测试它,我复制了about.html文件,称为Portfolio.html,更改了其中的一些内容,并在浏览器中输入了/#/pages/portfolio ,然后显示了presto Portfolio.html。

Updated Added $apply and $compile to the html so that dynamic content can be injected. 更新将 $ apply和$ compile添加到html,以便可以注入动态内容。

I think the easiest way to do such thing is to resolve the routes later, you could ask the routes via json, for example. 我认为最简单的方法是稍后解析路由,例如,可以通过json询问路由。 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. 确认我在配置阶段通过$ 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();
    });
});

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.$ro​​ute

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. 不幸的是,路由系统非常有限-有关此主题的讨论很多,并且已经提出了一些解决方案,即通过创建多个命名视图等。但是,现在,ngView指令在每个路由上仅提供一个视图,一对一的基础。 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). 您可以通过多种方式进行操作-更简单的方法是将视图的模板用作加载器,并在其中添加<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服务,在这里进行详细介绍:

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

Not sure why this works but dynamic (or wildcard if you prefer) routes are possible in angular 1.2.0-rc.2... 不确定为什么这样可行,但是在角度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. 无需在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. '/:a'是我发现的唯一一个可以达到此目的的变量。.'/: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.. 所有值都会触发动态控制器-因此没有“否则”的情况,但是,我认为这是您在动态或通配符路由方案中需要的。

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. 这允许routeProvider接受与子字符串匹配的参数,即使它们包含斜杠(即使它们以星号而不是冒号作为前缀)也是如此。 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 . 例如,诸如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. 我自己(使用1.1.5)对其进行了测试,并且效果很好。 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. 请记住,每个新URL都会重新加载您的控制器,因此,要保持任何状态,您可能需要使用自定义服务。

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;

    }

})();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM