JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
<script src="https://rawgit.com/TheSharpieOne/angular-off-click/master/offClick.js"></script>
<div data-ng-app="myApp" ng-controller="ctrl">
<button id="toggleAll" data-ng-click="toggleAll()">Toggle All</button>
<div ng-repeat="item in items track by $index">
<button id="toggle{{$index}}" data-ng-click="items[$index] = !items[$index]">Toggle</button>
<div id="box-thing" data-off-click="items[$index] = false" data-off-click-if="items[$index]" data-off-click-filter="'#toggleAll,#toggle'+$index" data-ng-show="items[$index]">Clicking outside of this will close this</div>
</div>
</div>
CSS
#toggle{
padding: 5px 10px;
margin: 10px;
}
#box-thing{
padding: 5px;
border: 2px solid #ccc;
}
JavaScript
angular.module('offClick', [])
.directive('offClick', ['$document', '$rootScope', '$timeout', '$parse', function ($document, $rootScope, $timeout, $parse) {
function targetInFilter(target, filter) {
if (!target || !filter) return false;
var elms = angular.element(document.querySelectorAll(filter));
var elmsLen = elms.length;
for (var i = 0; i < elmsLen; ++i)
if (elms[i].contains(target)) return true;
return false;
}
return {
restrict: 'A',
compile: function ($element, attr) {
var fn = $parse(attr.offClick);
return function (scope, element) {
var offClickFilter;
if (attr.offClickIf) {
$rootScope.$watch(function(){
return $parse(attr.offClickIf)(scope);
}, function (newVal, oldVal) {
if (newVal && !oldVal) {
$timeout(function () {
$document.on('click', handler);
});
} else if (!newVal) {
$document.off('click', handler);
}
});
} else {
$document.on('click', handler);
}
attr.$observe('offClickFilter', function (value) {
offClickFilter = scope.$eval(value);
});
function handler(event) {
// This filters out artificial click events. Example: If you hit enter on a form to submit it, an
// artificial click event gets triggered on the form's submit button.
if (event.pageX == 0 && event.pageY == 0) return;
var target = event.target || event.srcElement;
if (!(element[0].contains(target) || targetInFilter(target, offClickFilter))) {
...