AngularJS 路由中的动态部分参数

14

我正在处理一个angularjs网站,并且在Rails和php的Laravel中有路由方面的工作经验。在Laravel中,我们可以动态地创建一组类似于以下内容的路由:

  foreach($cities as $city):
    Route::get($city.'/hotels');
    Route::get($city.'/{slug}');

  endforeach;                      

在Laravel中,我们定义了一系列不同的路由,它们在技术上看起来几乎相同,除了cityslug的值不同。

在这种情况下,我发现angularJS在定义路由方面有点受限。老实说,我有点迷失了。

更新

我做了一些修改 - 基本上我设置了一个服务,从我的数据库中检索资产,例如在这种情况下城市和类别的列表。我正在尝试做到这一点:

如果{slug}在从我的API检索到的类别数组中,则使用我的ListController和列表视图,但如果没有,则改用我的SingleVenueController和单个视图。这是我目前的代码,但它不起作用:(

  appRouteProvider.when('/:city/:slug', {
      templateUrl : function(sharedParams, $routeParams){
        t = sharedParams.getCurrentPageType($routeParams);
        if(t=='list'){
          return '../../app/templates/list.html';
        }
        if(t=='single'){
          return '../../app/templates/single.html';
        }

      },
      controller  :  function(sharedParams, $routeParams){
        t = sharedParams.getCurrentPageType($routeParams);
        if(t=='list'){
          return 'ListsController';
        }
        if(t=='single'){
          return 'SingleController';
        }
      },


    resolve:{
      sharedParamsData:function(sharedParams){
        return sharedParams.promise;
      },
    }
  })

在上面的代码中,sharedParams是一个服务,而getCurrentPageType仅检查url slug以决定要发送回哪个控制器 - 但它实际上并没有起作用 :(

你是在使用 ui-router 还是 ng-route - Merlin
1
好的,您可以在配置中插入一个服务,然后按城市检索列表和地图。 - Joao Polo
现在先谈论ng-route - 我对你使用服务的解决方案很感兴趣,你怎么做到的? - Ali
我对我的代码进行了修改,但它似乎并没有正常工作。你能否给我提供一些想法? - Ali
你是否遇到了错误? - John Roca
你想动态创建路由或让代码正常工作吗? - Pankaj
4个回答

6
如何定义带参数的单个路由? 在AngularJS v1.x中,你可以定义任意数量的路由,并且可以使用参数或查询。
.config(function($routeProvider, $locationProvider) {
  $routeProvider
   .when('/city/:slug', {
    templateUrl: 'book.html',
    controller: 'BookController',
    resolve: {
     // you can also retrieve some data as a resolved promise inside your route for better performance.
  }
})

参考:https://docs.angularjs.org/api/ngRoute/service/$route

$route 是 AngularJS ngRoute 模块中的服务。它负责将 URL 映射到视图和控制器以及在路由变化时协调动态数据加载。


问题在于城市可以是动态值,例如来自数据库中的城市列表,或者上述URL也可以是静态页面,例如/site/contact或/about-us。 - Ali
你弄错了,伙计。你不需要直接从数据库中渲染,而是从前端渲染模板,并从服务器获取数据,其中城市=???在路由的解析中。 - mxncson
我已经部分解决了这个问题,但在加载正确的控制器和视图方面遇到了一些问题 - 我已经更新了我的代码,请帮忙看看 - 它还没有起作用.. - Ali

2
appRouteProvider.when('/:city/:slug', {
templateUrl : 'dafault.html',
controller  :  'DefaultController',
resolve:{
    factory: function($routeParams, $http, $location, sharedParams){
        var city = $routeParams.city;
        var slug = $routeParams.slug;
        var deferred = $q.defer();

        sharedParams.getCurrentPageType($routeParams).then(function(t) {
            if(t=='list'){
                $location.path('/' + city + '/' + slug + '/list');
                deferred.resolve();
            }
            else if(t=='single'){
                $location.path('/' + city + '/' + slug + '/single');
                deferred.resolve();
            } else {
                deferred.reject();
            }

        });

        return deferred.promise;
    },


 }
});
appRouteProvider.when('/:city/:slug/list', {
    templateUrl: '../../app/templates/list.html',
    controller: 'ListsController',
});
appRouteProvider.when('/:city/:slug/single', {
    templateUrl: '../../app/templates/single.html',
    controller: 'SingleController',
});

你可以使用单独的路由来完成。思路是当用户进入主要路由时,首先从后端获取数据进行解析。如果条件满足,则将解析函数重定向到具体路由;如果不满足,则不会通过。


2

在 Angular 中,服务不能在配置阶段注入,因为它们只有在应用的运行阶段才可用。

然而,有一种技巧可以在配置阶段加载 $http 服务,你可以使用此技巧来加载城市/类别并设置路由。与此同时,由于控制器直到运行阶段才注册,因此可以使用 $controllerProvider 在配置阶段预先注册控制器:

app.config(function ($routeProvider, $controllerProvider) {
  $controllerProvider.register('ListController', ListController);
  $controllerProvider.register('SingleController', SingleController);

  // wire the $http service
  var initInjector = angular.injector(['ng']);
  var $http = initInjector.get('$http');
  ...
});

现在,您可以调用API以获取城市(或其他内容),并在注册每个路由时进行迭代:
  ...
  // fetch the cities from the server
  $http.get('/cities')
  .then(function (response) {
    var cities = response.data;

    for(var i = 0; i < cities.length; i++){
      $routeProvider
      // assuming each city object has a `name` property
      .when('/' + cities[i]['name'] + '/:slug', {
        templateUrl: getTemplate(cities[i]['name']),
        controller: getController(cities[i]['name'])
      })
    }
  });
  ...

请注意,我使用的是getTemplategetController方法,它们分别返回templateUrl和相关控制器名称字符串,使用普通的switch表达式。您可以选择自己的方法。

Plunkr演示

注意:

虽然具有templateUrl路由选项属性的函数可以用于设置自定义模板,但当您在controller属性旁边使用函数时,Angular将其视为控制器的构造函数。因此,在该函数中返回控制器的名称不起作用。


0

正如Ahmad在他的答案中指出的那样,如果您将一个函数传递给controller,它将被视为控制器的构造函数。 此外,在应用程序的配置块中无法动态注入服务。

因此,您可以将sharedData服务移动到单独的应用程序中(在我的下面的代码中,我使用了appShared作为定义此服务的单独应用程序),然后使用angular.injector访问它。这样,您就不必将其定义为templateUrl / controller函数的参数。

顺便说一句,您无法向templateUrl函数传递自定义参数(参考:https://docs.angularjs.org/api/ngRoute/provider/$routeProvider

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

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

现在针对控制器,使用$controller根据您的条件动态加载ListsControllerSingleController。 一旦加载完成,请使用angular.extend扩展您当前的控制器(由您的控制器函数定义),以便它继承动态加载控制器的所有属性和方法。

在此处检查完整代码:http://plnkr.co/edit/ORB4iXwmxgGGJW6wQDy9

app.config(function ($routeProvider) {
    var initInjector = angular.injector(['appShared']);
    var sharedParams = initInjector.get('sharedParams');

    $routeProvider
    .when('/:city/:slug', {
        templateUrl: function ($routeParams) {
            console.log("template url - ");
            console.log($routeParams);
            var t = sharedParams.getCurrentPageType($routeParams);
            console.log(t);
            if (t == 'list') {
                return 'list.html';
            }
            if (t == 'single') {
                return 'single.html';
            }

        },
        controller: function ($routeParams, $controller, $scope) {
            //getController(cities[i]['name'])
            console.log("controller - ");
            console.log($routeParams);
            var t = sharedParams.getCurrentPageType($routeParams);
            console.log(t);
            if (t == 'list') {
                angular.extend(this, $controller('ListsController', { $scope: $scope }));
            }
            if (t == 'single') {
                angular.extend(this, $controller('SingleController', { $scope: $scope }));
            }
        }
    });


});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接