可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to validate certain condition before the browser follow the link dynamically created by ui-router.
I was looking into $rootscope.$on('$stateChangeStart', ..)
but I have no access to the controller.$scope
from there. I also need to use this in several places in the application and would be cumbersome.
Keep in mind that ui-sref
is linked to ui-sref-active
(work together), so i can't remove ui-sref
and, by say, to use $state.$go('some-state')
inside a function called with ng-click
.
The condition should be evaluated inside a $scope function
and on on-click event
(before-transition with the ability to cancel it)
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
回答1:
This answer inspired me to create a directive that allows me to interrupt the chain of events that end up changing state. For convenience and other uses 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
回答2:
You can use a scope function that will either returns :
- no state
an existing state
like 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
}
href
attribute will be created only when the function returns an existing state string.
Alternatively, you could do a (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
回答3:
The easiest workaround to conditionally achieve routing without tinkering with directives, scope etc was a workaround i found here - https://github.com/angular-ui/ui-router/issues/1489
<a ui-sref="{{condition ? '.childState' : '.'}}"> Conditional Link </a>
回答4:
You can always double up on the 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
回答5:
Based on the answers to How to dynamically set the value of ui-sref
you can create a function in your scope for building the URL:
$scope.buildUrl = function() {
return $state.href('somestate', {someParam: 'someValue});
};
And then conditionally append 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 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>
回答6:
No need for complicated directives or hacks. The following works fine and allows for specific handling on click of non-sref
items:
<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 the items which don't have an item.sref
:
this.click = function(item, event) {
if (!item.sref) {
event.preventDefault();
//do something else
}
};
回答7:
I know this is an old question, but for future reference I wanted to offer an alternative solution since I didn't see it in any of the answers so far.
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');
}
}
回答8:
Possible solution for those who still need ng-click
working on ui-sref
component or its parents.
My solution is to use href
instead of ui-sref
and to modify Emanuel's directive a bit to be able to stop href
and ng-click
calls separately.
Planker.
Though it has a few restrictions:
- will not work with
ui-sref
- you should have different urls for each state because of previous restriction
ui-sref-active
will not work either