web-dev-qa-db-fra.com

AngularJs $ watch sur $ location.search ne fonctionne pas lorsque reloadOnSearch est faux

Mon routeProvider pour la route a reloadOnSearch réglé sur false :

 $routeProvider
     .when(
        "/film/list",
         {
          templateUrl: '/film/list.html', 
          controller: FilmListController,
          reloadOnSearch: false
          } 
          ....

  )

J'ai fait cela parce que je ne veux pas que le contrôleur entier soit rechargé après les changements de chaîne de requête, mais je l'utilise toujours et l'url ressemble à ceci: film/list?sort=isbn&order=asc&offset=0. Maintenant, chaque fois que la chaîne de requête change, je veux appeler une fonction depuis mon contrôleur. J'ai donc essayé de configurer une $ watch dans le contrôleur:

$scope.location = $location;
$scope.$watch( 'location.search()', function( search) {
        $scope.list();
 });

Mais ça ne marche pas. Si je mets $ watch pour surveiller les changements d'un paramètre individuel d'une chaîne de requête, alors cela fonctionne. Mais je ne veux pas définir $ watch pour chaque paramètre de ma chaîne de requête. La solution que j'utilise maintenant est la suivante:

$scope.location = $location;
$scope.$watch( 'location.url()', function( url ) {
    if($location.path() == '/film/list')
        $scope.list();
 });

Donc, au lieu de regarder pour la recherche, je regarde toute l'URL, puis je vérifie si le chemin est celui que j'ai défini dans routeProvider pour appeler conditionnellement le une fonction. Ce que je n'aime pas dans cette solution, c'est que je dois saisir explicitement la valeur de $ location.path à faire correspondre.

Quelqu'un peut-il suggérer une meilleure solution et peut-être m'expliquer pourquoi $ watch ne fonctionne pas pour $ location.search ( ) ?

45
MBozic

Vous pouvez écouter $routeUpdate événement dans votre contrôleur:

$scope.$on('$routeUpdate', function(){
  $scope.sort = $location.search().sort;
  $scope.order = $location.search().order;
  $scope.offset = $location.search().offset;
});
77
Stewie

Dans le cas où vous n'utilisez pas la résolution d'itinéraire d'Angular ou si vous voulez simplement savoir à chaque fois que $ location change, il y a un événement juste à cet effet

$rootScope.$on('$locationChangeSuccess', function(event){
        var url = $location.url(),
            params = $location.search();
})
105
Le Duc Duy

La réponse des Stewies est correcte, vous devriez écouter les événements $routeUpdate Pour cela car c'est plus efficace.

Mais pour expliquer pourquoi votre montre ne fonctionne pas; lorsque vous regardez location.search(), vous regardez si la référence renvoyée par la méthode de recherche est la même ou non. Et il renverra la référence au même objet chaque fois que vous l'appelerez, c'est pourquoi votre montre ne se déclenche pas. Autrement dit, même si les paramètres de recherche changent, c'est toujours le même objet qui est renvoyé. Pour contourner cela, vous pouvez passer true comme troisième argument à $watch. Cela indiquera Angular à comparer par valeur, pas par référence. Mais soyez prudent lorsque vous créez de telles montres, car elles consommeront plus de mémoire et prendront plus de temps à s'exécuter. C'est pourquoi vous devriez le faire comme dit Stewart.

26
Anders Ekdahl

Utilisation

$scope.$watch(function(){ return $location.search() }, function(params){
    console.log(params);
});

au lieu.

10
Thomas Decaux

$ watch (watchExpression, listener, [objectEquality]);

watchExpression => devrait être soit

  1. Une chaîne évaluée comme expression ou
  2. Une fonction appelée avec la portée actuelle comme paramètre

Alors ici, vous devez passer votre premier paramètre en tant que fonction.

Exemple JavaScript =>

$scope.$watch (
                function () { return $scope.$location.search(); };
                function (value) { console.log(value); } 
              );

exemple TypeScript =>

this.$scope.$watch (
                     () => { return this.$location.search(); },
                     (value: any) => { console.log(value); }
                   ) ;

Cela a fonctionné pour moi.

Regardez le changement sur routeUpdate comme ceci dans le contrôleur:

 $scope.$watch('$routeUpdate', function(){
     $scope.sort = $location.search().sort;
     $scope.order = $location.search().order; 
 });
1
CodeOverRide