I have a list of "toggleable" items. When you click on the "toggleable" element, the element expands using ng-show directive. If clicked inside the item stays open, but if you click elsewhere the item contracts.
The way I implemented this is using a directive, that exposes a bound attribute isOpen. The value of isOpen is changed within the directive link function. On element click the value of isOpen is set to true and binds a close function to the $document click event. If clicked outside the element the close function is called, setting isOpen to false and unbinding the document click event.
This works fine for a single instance of this directive, but if two or more instances are introduced, the close function of every element other than the first clicked fails to set the respective isOpen attribute to false.
Here is a Plunker: http://plnkr.co/edit/ZNTRc2uL73kFZJmYOvhh?p=preview
The directive looks like this:
app.directive('myToggle', ['$document', function ($document) {
var closeToggle = null;
return {
restrict: 'A',
scope: { isOpen: '=myToggle' },
link: link
};
function link(scope, element, attributes) {
scope.$on('$locationChangeSuccess', function () { if (closeToggle) closeToggle(); });
element.bind('click', function() {
closeToggle = function(event) {
if (event)
if (element.parent().find(event.target).length != 0 && scope.isOpen)
return false;
$document.unbind('click', closeToggle);
scope.$apply(function () {
scope.isOpen = false;
});
closeToggle = angular.noop;
};
if (!scope.isOpen) {
scope.$apply(function() {
scope.isOpen = true;
});
$document.bind('click', closeToggle);
}
});
};
}]);
app.directive('myToggleCard', [function () {
// Usage:
//
// Creates:
//
var directive = {
link: link,
restrict: 'E',
template: '<a data-my-toggle="isOpen" data-ng-show="!isOpen" href="">ClickMe</a><div data-ng-if="isOpen"> Extra Content </div>',
replace: true,
scope: {
}
};
return directive;
function link(scope, element, attrs) {
scope.isOpen = false;
}
}]);
and the html looks like this:
<div>
<div>
<my-toggle-card></my-toggle-card>
<my-toggle-card></my-toggle-card>
<my-toggle-card></my-toggle-card>
<my-toggle-card></my-toggle-card>
</div>
</div>