1

http://plnkr.co/edit/hqXGl47EJ0wVaEgoXk3X?p=preview

I'm trying to find the best way to accomplish this. Basically there are several popovers we have in our app, for fuzzy search, additional options, help tips etc etc.

When any of them are open, they need to be closeable if the user clicks anywhere else outside of it, like the body.

vs.togglePopover = function() {
    vs.searchPopoverDisplay = vs.searchPopoverDisplay === false ? true: false;
};

The ng-click I have on the body currently:

vs.closePopovers = function() {
    PopFactory.hidePopovers();
};

This contacts a factory service which gets the scope of all controllers/directives that have a popover and if they are open, close them.

Of course this then makes the popovers unusable since as soon as you click the button to open the popover, the main app.js controller detects a body click and closes it.

var hidePopovers = function() {
    searchPopover     = ScopeFactory.getScope('search');
    tagsSearchPopover = ScopeFactory.getScope('tagsPopover');
    tagsSortPopover   = ScopeFactory.getScope('tagsSearch');
    tagsPanel         = ScopeFactory.getScope('tagsPanel');

    // is this popover open?
    // if so close it, see the problem?
    if (searchPopover.searchPopoverDisplay) {
        searchPopover.searchPopoverDisplay = false;
    }

    if (tagsSearchPopover.tagSearchPopover) {
        tagsSearchPopover.tagSearchPopover = false;
    }

    if (tagsSortPopover.tagsPopoverDisplay) {
        tagsSortPopover.tagsPopoverDisplay = false;
    }

    if (tagsPanel.showingTagSearchInput) {
        tagsPanel.showingTagSearchInput = false;
    }
};

return {
    hidePopovers : hidePopovers
};

How is this feature normally addresses in apps with popovers?

Leon Gaban
  • 36,509
  • 115
  • 332
  • 529

1 Answers1

1

Why not use an event?

On click:

vs.closePopovers = function() {
    $rootScope.$broadcast('closeAllPopovers');
};

Then, in each popover's scope:

scope.$on('closeAllPopovers', function(){
    close(); // Or however you close a popover
});

Angular Documentation for $on


Using the Plunk linked in comments:

When clicking on the button, you can see a log message from both the button click and the body click (good job on the logging BTW). This means that your single click on the button is being processed by button (opening the popover) and the by the body (closing the popover).

Take a look at this Plunk

To stop this behavior, you need to tell the ng-click event to stop propagating up the hierarchy of elements. Thankfully, this is very easy once you know to do it. Related SO Question (I prefer the second answer, I don't like excess code in the .html)

Community
  • 1
  • 1
Vlad274
  • 6,514
  • 2
  • 32
  • 44
  • So this won't close the popover immediately after just opening it? Will try it out... – Leon Gaban May 07 '15 at 15:19
  • @LeonGaban Please note my edit. $emit goes upwards in scope, $broadcast goes downwards – Vlad274 May 07 '15 at 15:20
  • @LeonGaban No, when using $on, the code will only execute on that event (unlike $watch, which I believe is what you are referencing) – Vlad274 May 07 '15 at 15:23
  • It's closing immediately, but yeah I'll try using $emit to set a thisPopover is open, but I'm getting the feeling that Broadcast will still close it immediately :( – Leon Gaban May 07 '15 at 15:23
  • @LeonGaban If it is closing immediately, I think you should check that your "onClick" function isn't being called incorrectly. – Vlad274 May 07 '15 at 15:26
  • I've updated my plnkr here: http://plnkr.co/edit/hqXGl47EJ0wVaEgoXk3X?p=preview now it's not opening at all :( – Leon Gaban May 07 '15 at 15:33
  • Thanks! :D forgot about stopping event propagation `$event.stopPropagation();` – Leon Gaban May 07 '15 at 16:42