In the project I’m working on right now, we needed a way to disable some input fields based on a condition which is pretty common. I ended up writing a directive to reduce the amount of duplicated code and keeping it clean and simple. However, there was one problem, we didn’t use the default checkboxes. Instead, we ended up using the icons from fonts-awesome library (Checked Icon, Unchecked Icon).

Here is an example of how we implemented the checkbox:

1
2
3
<i aria-hidden="true" ng-click="doStuff()" ng-class="checked ? 'fa fa-check-square-o' : 'fa fa-square-o'"></i>
<input type="checkbox" style="display: none" ng-model="form.input1">

Applying the directive on the input field doesn’t really work since it is hidden. The right thing to do is to apply the directive on the <i> tag itself. However, disabling <i> doesn’t do much, it will still allow clicking and thus firing off the function within ng-click.

The Solution

I spend hours looking for a simple solution that will do something along the lines of event.stopPropagation() when the checkbox icon is clicked. This should be enough to prevent ng-click being triggered.

At the end, I managed to find the solution (see below).

1
2
3
4
5
6
7
8
9
10
11
12
13
app.directive('stopNgClick', [function () {
return {
restrict: 'A',
link: {
pre: function (scope, element, attrs) {
element.bind('click touchstart', function (e) {
e.stopImmediatePropagation();
e.preventDefault();
});
}
}
};
}]);

The problem I was facing was due to the directive is doing default postLink, and after changing it to preLink everything worked as expected.

Additional Reading

Compile, Pre, and Post Linking in AngularJS is a good article that focuses on the execution order of Linking and Compile.