2012-12-02 27 views
14

Quando si utilizza ng-view e $routeProvider, è possibile iniettare $routeParams per ottenere i valori del percorso, ad esempio /foo/:id/:user/:item. C'è un modo per impostare quei parametri nel percorso? Qualcosa come $routeParams.id = 3, e poi hanno riflesso nell'URL.

So che questo effetto potrebbe essere raggiunto tramite $location.path(), ma spero di ottenere un livello più alto di astrazione che non richieda la manipolazione delle stringhe.

risposta

12

Ecco come sono riuscito a risolvere il problema.

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

dichiarazione Module + percorso definizione:

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

Template:

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

Riferimenti:

1

Come pure, se si desidera che l'associazione dati a due vie per i parametri URL con $ posizione, questo si una buona funzione aiuterà.

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

Io uso questo da un servizio condiviso, è per questo campo di applicazione è passata in

+1

Mi piace! Si noti, tuttavia, che questo non è un collegamento dati bidirezionale. Quando viene chiamata la funzione, la variabile scope viene impostata sul valore corrente del parametro URL e, successivamente, il parametro URL viene aggiornato quando la variabile scope cambia. Se due ambiti si collegano allo stesso parametro URL, un ambito che lo modifica non aggiornerà la variabile nell'altro ambito. Questo è sufficiente per molti scopi però. – tobek

+0

È vero, buon punto per quanto riguarda i diversi ambiti che si collegano allo stesso parametro URL. –

0

Io uso un servizio per creare un doppio senso di legame:.

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

nel controller:

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

È quindi possibile, ad esempio associare un ingresso alla url:

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

Potrebbe anche essere necessario impostare reloadOnSearch : false nel vostro percorso di configurazione, come non si vuole nell'ambito del controllore per essere distrutto e ricreato ogni volta che il ricerca po 'di cambiamenti url.

Problemi correlati