How to ensure that "ui-sref" is conditionally executed?

I want to check some conditions before the browser follows the dynamics created by ui-router.

I watched $rootscope.$on('$stateChangeStart', ..) , but I don't have access to controller.$scope . I also have to use this in several places in the application and will be cumbersome.

Keep in mind that ui-sref is associated with ui-sref-active (working together), so I cannot remove ui-sref and, say, use $state.$go('some-state') inside a function with ng-click .

The condition must be evaluated inside a $scope function and on-click event (before the transition with the possibility of its cancellation)

I need something like this:

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

I tried:

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

and

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

Even

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

But does not work.

Sandbox

+54
javascript angularjs angular-ui-router
Sep 01 '14 at 6:36
source share
8 answers

This answer inspired me to create a directive that allows me to break the chain of events that ultimately change state. For convenience and other purposes, it also prevents the execution of ng-click on the same element.

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

+62
Sep 03 '14 at 5:16
source share

You can use the scope function, which will either return:

  • no condition
  • existing condition

    So:

HTML:

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

JS scope:

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

href will only be created when the function returns an existing status bar.

Alternatively you can do (ugly):

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

Hope this helps

+25
Sep 01
source share

You can always double an element and show / hide conditionally

  <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
02 Sep '14 at 19:07
source share

The simplest workaround to conditionally achieve routing without using directives, scope, etc. there was a workaround i found here - https://github.com/angular-ui/ui-router/issues/1489

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

+5
Mar 09 '17 at 16:50
source share

Based on the answers to How to dynamically set the ui-sref you can create a function in your area to create a URL:

 $scope.buildUrl = function() { return $state.href('somestate', {someParam: 'someValue}); }; 

And then conditionally add it to the link with ng-href

 <a ng-href="{{ someCondition ? buildUrl() : undefined }}">Link</a> 

As you can see in the demo below, ng-href does not add the href attribute if the value is negative.

 angular.module('app', []) 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app"> <a ng-href="{{ condition ? 'http://thecatapi.com/api/images/get?format=src&type=gif' : undefined}}">This is the link</a> <br> <label for="checkbox"> <input type="checkbox" id="checkbox" ng-model="condition"> Link active? </label> </div> 
+2
Jun 12 '16 at 12:16
source share

No need for complicated directives or hacks. The following works fine and allows you to do some processing when you click non- sref elements:

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

And in the controller, a simple click handler for items that do not have item.sref :

 this.click = function(item, event) { if (!item.sref) { event.preventDefault(); //do something else } }; 
+1
Jun 26 '16 at 1:59
source share

I know this is an old question, but for a future reference, I wanted to offer an alternative solution, since I did not see it in any of the answers.

Desired:

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

Potential solution (template):

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

And in the controller:

 $scope.state = $state; $scope.navigateToState = navigateToState; function navigateToState() { if ($scope.model.valid) { $state.go('somestate'); } } 
+1
Apr 14 '17 at 12:37 on
source share

A possible solution for those who still need ng-click to work with the ui-sref or its parents.

My solution is to use href instead of ui-sref and modify the Emanuel directive a bit to be able to stop the href and ng-click calls individually.

Planker .

Although it has several limitations:

  • will not work with ui-sref
  • you must have different urls for each state due to previous restriction
  • ui-sref-active will not work.
0
Jun 29 '17 at 11:03 on
source share



All Articles