web-dev-qa-db-fra.com

Comment obtenir que "ui-sref" soit exécuté de manière conditionnelle?

Je veux valider certaines conditions avant que le navigateur ne suive le lien créé dynamiquement par ui-router. 

Je cherchais dans $rootscope.$on('$stateChangeStart', ..) mais je n'ai pas accès au controller.$scope à partir de là. J'ai également besoin de l'utiliser à plusieurs endroits de l'application, ce qui serait fastidieux. 

N'oubliez pas que ui-sref est lié à ui-sref-active (fonctionne ensemble), je ne peux donc pas supprimer ui-sref et, par exemple, utiliser $state.$go('some-state') dans une fonction appelée avec ng-click.

La condition doit être évaluée dans un $scope function et sur on-click event (avant-transition avec la possibilité de l'annuler)

J'ai besoin de quelque chose comme ça:

<li ui-sref-active="active">
      <a ui-sref="somestate" ui-sref-if="model.validate()">Go Somestate</a>
</li>

J'ai essayé:

<li ui-sref-active="active">
      <a ui-sref="somestate" ng-click="$event.preventDefault()">Go Somestate</a>
</li>

<li ui-sref-active="active">
      <a ui-sref="somestate" ng-click="$event.stopImmediatePropagation()">Go Somestate</a>
</li>

Et

<li ui-sref-active="active">
    <a ui-sref="somestate">
       <span ng-click="$event.stopPropagation();">Go Somestate</span>
    </a>
</li>

Même

<li ui-sref-active="active">
      <a ui-sref="somestate" onclick="return false;">Go Somestate</a>
</li>

Mais ça ne marche pas.

BAC &AGRAVE; SABLE

56
rnrneverdies

Cette réponse m'a inspiré pour créer une directive qui me permet d'interrompre la chaîne d'événements qui finissent par changer d'état. Pour des raisons de commodité et d’autres utilisations, empêche également l’exécution de ng-click sur le même élément.

javascript

module.directive('eatClickIf', ['$parse', '$rootScope',
  function($parse, $rootScope) {
    return {
      // this ensure eatClickIf be compiled before ngClick
      priority: 100,
      restrict: 'A',
      compile: function($element, attr) {
        var fn = $parse(attr.eatClickIf);
        return {
          pre: function link(scope, element) {
            var eventName = 'click';
            element.on(eventName, function(event) {
              var callback = function() {
                if (fn(scope, {$event: event})) {
                  // prevents ng-click to be executed
                  event.stopImmediatePropagation();
                  // prevents href 
                  event.preventDefault();
                  return false;
                }
              };
              if ($rootScope.$$phase) {
                scope.$evalAsync(callback);
              } else {
                scope.$apply(callback);
              }
            });
          },
          post: function() {}
        }
      }
    }
  }
]);

html

<li ui-sref-active="active">
      <a ui-sref="somestate" eat-click-if="!model.isValid()">Go Somestate</a>
</li>

PLUNKER

67
rnrneverdies

Vous pouvez utiliser une fonction de portée qui renverra soit:

  • pas d'état
  • un état existant

    ainsi :

HTML:

<li ui-sref-active="active">
      <a ui-sref="{{checkCondition()}}">Go Somestate</a>
</li>

JS portée:

$scope.checkCondition = function() {
    return model.validate()
        ? 'someState'
        : '-' // hack: must return a non-empty string to prevent JS console error
}

L'attribut href sera créé uniquement lorsque la fonction renvoie une chaîne d'état existante.

Alternativement, vous pouvez faire un (moche):

<li ui-sref-active="active">
      <a ui-sref="somestate" ng-if="model.validate()">Go Somestate</a>
      <span ng-if="!model.validate()">Go Somestate</span>
</li>

J'espère que cela t'aides

27
Cétia

La solution de contournement la plus simple pour réaliser conditionnellement un routage sans modifier les directives, la portée, etc. était une solution de contournement trouvée ici - https://github.com/angular-ui/ui-router/issues/1489

<a ui-sref="{{condition ? '.childState' : '.'}}"> Conditional Link </a>

8
jetpackdata.com

Vous pouvez toujours doubler l'élément et afficher/masquer conditionnellement

    <li ui-sref-active="active">
          <a ng-show="condition1" style="color: grey">Start</a>
          <a ng-hide="condition1" ui-sref="start">Start</a>
    </li>

http://plnkr.co/edit/ts4yGW?p=preview

7
Chris T

Pas besoin de directives compliquées ou hacks. Ce qui suit fonctionne bien et permet un traitement spécifique au clic d’éléments non -sref:

<a 
  ng-repeat="item in items" ui-sref="{{item.sref || '-'}}" 
  ng-click="$ctrl.click(item, $event)"
>...</a>

Et dans le contrôleur, un simple gestionnaire de clic pour les éléments qui n’ont pas de item.sref:

this.click = function(item, event) {
  if (!item.sref) {
    event.preventDefault();
    //do something else
  }
};
3
Adam Reis

Je sais que c’est une vieille question, mais pour référence future, je souhaitais proposer une solution de remplacement car je ne l’avais pas trouvée dans les réponses jusqu’à présent.

Souhaité:

<li ui-sref-active="active">
    <a ui-sref="somestate" ui-sref-if="model.validate()">Go Somestate</a>
</li>

Solution potentielle (modèle):

<li ng-class="{ active: state.current.name === 'somestate' }">
    <a ng-click="navigateToState()">Go Somestate</a>
</li>

Et dans le contrôleur:

$scope.state = $state;
$scope.navigateToState = navigateToState;

function navigateToState() {
  if ($scope.model.valid) {
    $state.go('somestate');
  }
}
1
David Meza

Solution possible pour ceux qui ont encore besoin de ng-click travailler sur le composant ui-sref ou ses parents.

Ma solution est d'utiliser href au lieu de ui-sref et de modifier légèrement la directive Emanuel pour pouvoir arrêter les appels href et ng-click séparément. 

Planker .

Bien qu'il y ait quelques restrictions:

  • ne fonctionnera pas avec ui-sref
  • vous devriez avoir des URL différentes pour chaque état en raison de la restriction précédente
  • ui-sref-active ne fonctionnera pas non plus
0
andrfas