AngularJS路由中的动态部分参数

时间:2016-09-27 14:36:40

标签: javascript php angularjs laravel

我正在使用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来决定要发回的控制器 - 但它根本不起作用:(

4 个答案:

答案 0 :(得分:6)

如何使用参数定义单个路径? 在angularjs v1.x中,您可以使用尽可能多的参数xor query

定义所需的路径
.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

答案 1 :(得分: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 :(得分:2)

Angular中的服务无法在配置阶段注入,因为它们仅在Angular应用程序的 run 阶段可用。

然而,在配置阶段加载$http服务trick,您可以使用该服务加载城市/类别并设置路线。同时,由于控制器在运行阶段之前尚未注册,因此您可以在配置阶段使用$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 Demo

<强> 注意:

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

答案 3 :(得分:0)

正如Ahmad已经在他的answer中指出的那样,如果你将函数传递给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 }));
            }
        }
    });


});