Reputation: 1834
Here is a directive in which I'm attempting to disable a link based on a model value:
app.directive('disableable', function($parse){
return {
restrict: 'C',
require: '?ngClick',
link: function (scope, elem, attrs, ngClick) {
if (attrs.disable){
var disable = $parse(attrs.disable);
elem.bind('click', function (e) {
if (disable(scope)){
e.preventDefault();
return false;
}
return true;
});
scope.$watch(disable, function (val) {
if (val){
elem.addClass('disabled');
elem.css('cursor', 'default');
}
else {
elem.removeClass('disabled');
elem.css('cursor', 'pointer');
}
});
}
}
};
});
I want to be able to disable all link actions, regardless of whether they use simple hrefs or ngClick actions. Hrefs work fine because of the preventDefault call, but I can't figure out how to dig into the ngClick and prevent it from firing. The bind I'm doing on the click event isn't working because it seems ngClick is binding its own handler that I have no control over. Is there anything I can do?
jsFiddle: http://jsfiddle.net/KQQD2/2/
Upvotes: 7
Views: 7422
Reputation: 60406
Use event.stopImmediatePropagation
.
From MDN:
If several listeners are attached to the same element for the same event type, they are called in order in which they have been added. If during one such call, event.stopImmediatePropagation() is called, no remaining listeners will be called.
...
elem.bind('click', function (e) {
if (disable(scope)){
e.stopImmediatePropagation();
return false;
}
return true;
});
...
Upvotes: 9
Reputation: 38716
I'd probably take a slightly different tack. Instead of trying to pry yourself into ng-click using another directive. I'd just write my own version of ng-click and use that instead then it could be toggled on/off using a separate attribute. If you did that then the code you wrote above wouldn't need to change much in order to do this, and you could just use that directive in place of ng-click.
app.directive('enabled-click', function() {
return {
scope: {
enabledClick: '&',
enabled: '='
},
restrict: 'A',
link: function( scope, element, attributes ) {
element.bind('click', function(event) {
if( scope.enabled ) {
if( element.target ) {
return true; // external link
} else {
scope.enabledClick();
return false;
}
} else {
event.preventDefault();
return false;
}
} );
scope.$watch( 'enabled', function(val) {
if( val ) {
element.removeClass('disabled');
} else {
element.addClass('disabled');
}
});
}
};
});
Then to use it:
<a href="#something" enabled-click="doSomething()" enabled="!disable">Blah</a>
Upvotes: 0
Reputation: 12437
You could do simply change your ng-click to disableIt || tellAboutIt()
and it'll work as-is. e.g
<a class="disableable" target="_blank" ng-click="disableIt || tellAboutIt()">
ngClick disableable link</a>
Full code:
HTML (i've removed the 'disabled' attributes because they're useless as they don't work on anchor tags):
<div ng-app="app" ng-controller="appCtrl">
<a class="disableable" target="_blank" ng-click="disableIt || tellAboutIt()">
ngClick disableable link</a>
<br/><br/>
<a class="disableable" target="_blank" href="http://google.com">
href disableable link</a>
<br/><br/>
<input type="checkbox" ng-model="disableIt" /> Disable links
</div>
Angular (I've made your directive more compact):
app.directive('disableable', function($parse){
return {
restrict: 'C',
link: function (scope, elem, attrs) {
scope.$watch('disableIt', function (val) {
if (val) {
elem.addClass('disabled');
elem.css('cursor', 'default');
elem.bind('click', function(e) {
e.preventDefault();
});
}
else {
elem.removeClass('disabled');
elem.css('cursor', 'pointer');
if (typeof elem.attr('ng-click') === 'undefined')
elem.unbind('click');
}
});
}
};
});
JSFiddle: http://jsfiddle.net/KQQD2/4/
Alternatively, you could check $scope.disableIt
is false before running the code inside tellAboutIt()
. e.g.:
$scope.tellAboutIt = function(){
if ($scope.disableIt === false) {
$window.alert('ngClick fired. This alert should not show when disabled.');
}
};
Upvotes: 4