2012-12-02 163 views
14

使用ng-view$routeProvider時,可以注入$routeParams以獲取路徑的值,如/foo/:id/:user/:item。有什麼方法可以在路徑中設置這些參數嗎?像$routeParams.id = 3之類的東西,然後反映在url中。

我知道這個效果可以通過$location.path()來實現,但我希望能夠進行更高級別的抽象,不需要字符串操作。

回答

12

以下是我設法解決問題的方法。

控制器

app.controller('MainCtrl', [ 
    '$scope', '$log', '$route', '$routeParams', '$location', 
    function(scope, console, route, routeParams, location) { 
    console.log('MainCtrl.create'); 
    scope.route = route; 
    scope.routeParams = routeParams; 
    scope.location = location; 

    //1. This needs to be enabled for each controller that needs to watch routeParams 
    //2. I believe some encapsulation and reuse through a service might be a better way 
    //3. The reference to routeParams will not change so we need to enable deep dirty checking, hence the third parameter 

    scope.$watch('routeParams', function(newVal, oldVal) { 
     angular.forEach(newVal, function(v, k) { 
     location.search(k, v); 
     }); 
    }, true); 
    }]); 

模塊聲明+路由定義

var app = angular.module('angularjs-starter', [], [ 
     '$routeProvider', '$locationProvider', 
     function(routeProvider, locationProvider) { 
     routeProvider.when('/main', { 
      template : 'Main', 
      controller : 'MainCtrl', 
      reloadOnSearch : false 
     }); 
     } ]); 

模板

<body ng-controller="MainCtrl"> 
    <a href="#/main">No Params</a> 
    <a href="#/main?param1=Hello&param2=World!">With Params</a> 

    <div ng-view></div> 

    <p> 
    <span>param1</span> 
    <input type="text" ng-model="routeParams['param1']"> 
    </p> 
    <p> 
    <span>param2</span> 
    <input type="text" ng-model="routeParams['param2']"> 
    </p> 

    <pre>location.path() = {{location.path()}}</pre> 
    <pre>routeParams = {{routeParams}}</pre> 
</body> 

演示

參考

1

同樣,如果你想用$ URL參數雙向數據綁定位置,這個si多功能將有所幫助。

bind_var_to_urlparam = function(variable_name, scope){ 
    // initial loading from urlparams and then 
    // set a watch function to update the urlparams on update 
    scope[variable_name] = $location.search()[variable_name]; 
    scope.$watch(variable_name, function(newVal, oldVal){ 
    var search_obj = {}; 
    search_obj[variable_name] = newVal; 
    $location.search(search_obj); 
    }); 
} 

我用這從一個共享服務,這就是爲什麼範圍在傳遞

+1

我喜歡它!但請注意,這不是真正的雙向數據綁定。當函數被調用時,範圍變量被設置爲URL參數的當前值,之後,當範圍變量改變時,URL參數被更新。如果兩個作用域綁定到相同的URL參數,則更改該作用域的一個作用域不會更新另一個作用域中的變量。儘管這對於許多目的來說已經足夠 – tobek

+0

這是真的,關於不同作用域綁定到相同的URL參數的好處。 –

0

我使用服務來創建一個雙向綁定:

angular.module('app').service('urlBinder', ['$location', function($location) { 
    this.bindOnScope = function(scope, name, urlParamName) { 
     // update the url when the scope variable changes 
     var unhookUrlUpdater = scope.$watch(name, function(newValue, oldValue) { 
      if (!angular.equals(oldValue, newValue)) { 
       $location.search(urlParamName, newValue); 
      } 
     }); 

     // update the scope variable when the url changes 
     var unhookScopeUpdater = scope.$on('$locationChangeSuccess', function() { 
      var value = $location.search()[urlParamName]; 

      if (!angular.equals(scope[name], value)) { 
       scope[name] = value; 
      } 
     }); 

     // return a function to remove the hooks. Note that since these hooks are set up on the scope passed in, if that scope gets destroyed (e.g. because the user went to a different page and the controller is no longer present), then the hooks will be removed automatically. 
     return function() { 
      unhookUrlUpdater(); 
      unhookScopeUpdater(); 
     }; 
    }; 

    // the same thing but using getter/setter functions for when you want to bind to something not on the scope 
    this.bind = function(scope, getter, setter, urlParamName) { 
     var unhookUrlUpdater = scope.$watch(getter, function(newValue) { 
      $location.search(urlParamName, newValue); 
     }); 

     var unhookScopeUpdater = scope.$on('$locationChangeSuccess', function() { 
      var value = $location.search()[urlParamName]; 

      if (!angular.equals(getter(), value)) { 
       setter(value); 
      } 
     }); 

     return function() { 
      unhookUrlUpdater(); 
      unhookScopeUpdater(); 
     }; 
    }; 
}]); 

在你的控制器:

angular.module('app').controller('ctrl', ['$scope', function($scope) { 
    // if binding to something on the scope: 
    urlBinder.bindToScope($scope, 'something', 'url-name'); 
    $scope.something = 'test'; 

    // or if the variable you want to bind isn't on the scope: 
    var someVariable; 
    urlBinder.bind(
     $scope, 
     function() { return someVariable; }, 
     function(value) { someVariable = value; }, 
     'url-name'); 
}]); 

然後可以例如綁定一個輸入網址:

<div ng-controller="ctrl"> 
    <input type="number" ng-model="something" /> 
</div> 

您可能還需要設置reloadOnSearch : false在路線的配置,因爲你不想讓控制器範圍內被摧毀和重建每當搜索位的URL變化。