Двусторонняя привязка к $routeParams? - программирование
Подтвердить что ты не робот

Двусторонняя привязка к $routeParams?

При использовании ng-view и $routeProvider можно ввести $routeParams, чтобы получить значения пути, например /foo/:id/:user/:item. Есть ли способ установить эти параметры в пути? Что-то вроде $routeParams.id = 3, а затем отразится на URL-адресе.

Я знаю, что этот эффект может быть достигнут через $location.path(), но я надеюсь на более высокий уровень абстракции, который не требует строковых манипуляций.

4b9b3361

Ответ 1

Вот как мне удалось решить проблему.

контроллер

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>

Demo

Ссылки

Ответ 2

Кроме того, если вы хотите двустороннюю привязку данных для параметров URL с $location, эта простая функция поможет.

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);
  });
}

Я использую это из общей службы, поэтому область пропускается.

Ответ 3

Я использую службу для создания двусторонней привязки:

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');
}]);

Затем вы можете, например, привязать вход к URL:

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

Вам также может потребоваться установить reloadOnSearch : false в конфигурацию маршрута, так как вы не хотите, чтобы область действия контроллера была уничтожена и воссоздана всякий раз, когда изменяется бит поиска URL.