Skip to content
This repository has been archived by the owner on Sep 10, 2019. It is now read-only.

suggestion: allow closing of off-screen menu by click outside of the menu #430

Closed
smh111976 opened this issue Feb 1, 2015 · 24 comments
Closed

Comments

@smh111976
Copy link

would it be a possibility to allow a user to hide an off-screen panel simply by clicking anywhere outside of the panel? As it works now, i believe you can only close an off-screen panel or menu by clicking on a zf-close or zf-toggle element. It would be great if, after a user opens/toggles an off-screen panel/menu, they could click anywhere on the viewport, outside of the panel, to close that panel.

@gakimball
Copy link
Contributor

Definitely, we need this functionality for off-canvas and panels.

@moondawg69
Copy link

+1

@jonathanmendes
Copy link

+1, especially for panels!

@soumak77
Copy link
Contributor

soumak77 commented Mar 6, 2015

+1

1 similar comment
@juniorgodoi
Copy link

+1

@ksr583
Copy link

ksr583 commented Mar 17, 2015

+1
I suppose an ng-if or ng-show on a fixed element that covers the rest of the content and has a zf-toggle would work, just need to figure out how to based that ng-if/ng-show on the state of the off-canvas menu. (Just downloaded foundation-apps for the first time tonight)

@maxcook
Copy link

maxcook commented Mar 27, 2015

any progress on this?

@soumak77
Copy link
Contributor

@gakimball I believe the same solution used for auto-closing of action sheets when clicked outside should also work for closing of off-canvas and panels. Perhaps refactor the code into a reusable service to be used for any component?

@gakimball
Copy link
Contributor

@maxcook We'd like to do this and the darkened overlay, but we haven't done any work on it yet. We'd certainly welcome a pull request if anyone wants to take a crack at it.

@soumak77 We have zfClosable, would it be possible to bake any hooks into that?

@soumak77
Copy link
Contributor

@gakimball did you mean zfClose? That could be used on the body with an element ID and if any click event reaches the body, it would be closed. There are a couple problems with that approach:

  1. You cannot specify more than one element to close, thus you cannot close the off-canvas AND panels with this method.
  2. All click events that open/toggle a component must now trap the event or else it'll bubble up to the body and close the component.
  3. Any click event inside the component must be trapped or it'll cause the component to close (for same reason as 2).
  4. The body element is usually defined in an index.html, where as all other components are defined else where (i.e. in views). Forcing a declaration on the body would cause a developer to have to know the id for every component used in their app, which becomes difficult once you start developing a large application.

I prefer the approach used by the actionsheets wherein the developer does not need to set anything up for the auto-close functionality to work as it's just part of the component (solves 4). It's basically doing the same thing as zfClose would be doing if added to the body, but works for multiple elements (solves 1). The slight difference is that the actionsheet logic checks to see if the click was within the actionsheet, and if so, it doesn't close the actionsheet (solves 3). This logic seems useful for off-canvas and panels as well. It also checks to make sure that the click didn't originate from an element used to open or close the component (solves 2). With some refactoring, the code used for actionsheets could also be used for off-canvas and panels. Any opposition to taking this approach?

The only thing I could think of for why this approach may not work is if a developer didn't want the auto-close functionality for that component. In this case an attribute could be added to the element which is read during the compile phase of the directive. If the attribute is present, the auto-close functionality is disabled, otherwise it is enabled by default.

I'll take a go at the PR since it should be fairly straightforward.

@soumak77
Copy link
Contributor

I was searching for zfClosable instead of zf-closable in the code base. Let me see what can be done with zf-closable.

@soumak77
Copy link
Contributor

Ok, so I think FoundationApi.closeActiveElements() (the code that makes use of the zf-closable attributes) could be used to solve this issue. At its most basic, one could expose FoundationApi in the scope and add the following to an element: ng-click="FoundationApi.closeActiveElements()". Adding that to the body element would solve this issue. This approach will still cause the component to close if the click originated from inside the component. To solve this, one could add ng-click="$event.stopPropagation()" to their component. I tested this with off-canvas and the off-canvas closes when clicked outside, but stays open when clicked inside. I don't have any panels in my app to test this with, but I'm sure it would work just the same.

I'm not a huge fan of this approach as it will not work for everyone. From what I can tell, F4A is being designed so that it could be used by anyone, regardless of how little or how much they know about angular. The solution above will require the FoundationApi to be exposed in the scope, which will require defining your own angular code (unless this can be done in the front matter, which I'm not sure it should be). To solve this, a reference to the FoundationApi service could be added to the $rootScope on loading of foundation so that the following could be used ng-click="$root.$foundation.closeActiveElements()" instead of ng-click="FoundationApi.closeActiveElements()". While most of the time adding something to the $rootScope is a bad design pattern, I think this will be ok as the foundation api is a core service that should be available everywhere.

@soumak77
Copy link
Contributor

After thinking about it, I still would prefer this feature to work out of the box with no additional code required, meaning the code to resolve this issue should reside inside the foundation code base, versus requiring additional angular directives to use this feature. Perhaps foundation could add a default click handler to the body which always calls closeActiveElements. The click handler could be smart and check where the click originated from and not close a component if the click was inside it. If a developer doesn't want their component auto-closed when clicked outside, they could add an attribute zf-auto-close-ignore or something of the like, so that the component is not closed by the body click handler, but would still be closed by usage of the zf-hard-toggle directive (which internally calls closeActiveElements).

@philippeluickx
Copy link

+1

4 similar comments
@tunecino
Copy link

+1

@sjoerdvanhal
Copy link

+1

@ViniciusTavares
Copy link

+1

@BrendonPierson
Copy link

+1

@Martinspire
Copy link

+1

Is this ever coming in? And how would you work around this untill its added?

@soumak77
Copy link
Contributor

soumak77 commented Nov 3, 2015

@Martinspire You can implement this feature my adding the following attribute to any element you want to have close the off canvas (in my example the off canvas has id app-menu).

ng-click="closeAppMenu()"

Where closeAppMenu is the following function on the scope. You might not need the $timeout anymore. It was originally added before some of the $$phase bugs were fixed in the framework.

$scope.closeAppMenu = function() {
  $timeout(function() {
    FoundationApi.publish('app-menu', 'close');
  });
};

Note that I did not add the click handler to the body as the body also contains the off canvas menu. I added the click handler to the root element containing my views so that clicking inside the off canvas does not lose the menu. In some cases where I need the menu to close when I click a link inside the off canvas, I've added the following element to the link:

zf-toggle="app-menu"

@zurbchris
Copy link
Contributor

Nearly done with this feature...

@zurbchris
Copy link
Contributor

Done. Add zf-close-all to the body tag in your markup.
At least with 1.2 release 😆

zurbchris added a commit that referenced this issue Dec 4, 2015
…n anything other than their respective contents. fixes #430
@rockinrocco
Copy link

This should really be somewhere in the offcanvas menu or panel documentation - this is something almost every designing for mobile will want.

@soumak77
Copy link
Contributor

ZURB has basically dropped support for this framework and it is now being developed by the community here: https://github.com/base-apps/angular-base-apps

Feel free to submit a PR to improve the documentation

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests