2012-12-02 12 views
14

Podczas korzystania z ng-view i $routeProvider, można wprowadzić $routeParams, aby uzyskać wartości ścieżki, takie jak /foo/:id/:user/:item. Czy istnieje sposób na ustawienie tych parametrów w ścieżce? Coś jak $routeParams.id = 3, a następnie mają to odzwierciedlenie w adresie URL.

Wiem, że efekt ten można osiągnąć poprzez $location.path(), ale mam nadzieję na wyższy poziom abstrakcji, który nie wymaga manipulacji ciągami.

Odpowiedz

12

Oto jak udało mi się rozwiązać problem.

Controller:

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

deklaracja Moduł + trasa definicja:

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

Szablon:

<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:

Referencje:

1

Jak dobrze, jeśli chcesz dwukierunkowe wiązania z danymi dla parametrów URL dolarów lokalizacja, to si funkcja mple pomoże.

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

Używam tego z udostępnionej usługi, dlatego zakres jest przekazywana w

+1

Podoba mi się! Należy jednak pamiętać, że nie jest to dwukierunkowe wiązanie danych. Po wywołaniu funkcji zmienna zasięgu jest ustawiana na bieżącą wartość parametru URL, a następnie parametr adresu URL jest aktualizowany po zmianie zmiennej zasięgu. Jeśli dwa zakresy łączą się z tym samym parametrem URL, zmiana zakresu nie spowoduje aktualizacji zmiennej w innym zakresie. Jest to jednak wystarczające dla wielu celów. – tobek

+0

To prawda, dobry punkt dotyczący różnych zasięgów powiązanych z tym samym parametrem URL. –

0

Używam usługę stworzyć dwukierunkowa wiążące.

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

W kontrolerze:

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

następnie można na przykład powiązać wejście do adresu URL:

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

Być może trzeba ustawić reloadOnSearch : false w config trasy, jak nie chcesz zakres kontroler zostać zniszczone i odtworzone gdy wyszukiwania nieco zmienia URL.

Powiązane problemy