question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Closing dropdown from child element causes Ember to skip child element action

See original GitHub issue

Not sure if it is a good place to ask this question it maybe not this plugin’s fault.

So here is the deal: I have dropdown content yielded to parent element and I want that when user click on any link in that content, dropdown would be closed. I do this by first registering dropdown with my component:

<div class="{{dropdownWrapperClass}}">
  {{#basic-dropdown registerAPI=(action 'registerDropdown') as |dropdown|}}
    {{#dropdown.trigger}}Trigger{{/dropdown.trigger}}
    {{#dropdown.content renderInPlace=true}}
      <ul class="{{dropdownMenuClass}}" {{action 'mouseDown' on='click'}}>
        {{yield}}
      </ul>
    {{/dropdown.content}}
  {{/basic-dropdown}}
</div>

Then when mouseDown action is called, I check if e.target is a link or button, here is component code:

mouseDown: function(e) {
  const $target = Ember.$(e.target);
  const ul = $target.parents(`.${this.get('dropdownMenuClass')}`)[0];
  if ($target.is('button, a:link') && ul) {
      this.get('dropdown').actions.close();
  }
  return false;
},

actions: {
  registerDropdown: function(dropdown) {
    this.set('dropdown', dropdown);
  },
}

When I do this, dropdown gets closed but the action that was assigned on the link does not get executed.

Now there is a workaround for this problem:

Ember.$(ul).css('opacity', '0'); // Hide the dropdown.content so the action will seem immediate to user
Ember.run.later(() => {
  Ember.$(ul).css('opacity', '1');
  self.get('dropdown').actions.close(); // Now really close it
 }, 100);

However I don’t like solutions based on some magic timeouts.

I dug into the code of previous plugin that I’ve used: rl-dropdown, looks like they’ve toggled display: none/block css property to control visibility of dropdown.content which worked fine.

I think that this use case is quite common, you do need to close dropdown when child of content is clicked, so there are couple of things I would like to suggest:

  1. It would be nice to add similar functionality that rl-dropdown has, that will allow users of plugin pass selector which will cause dropdown to close on matching elements, basically:
{{#dropdown.content closeOnClickClick='.button'}}
  1. If there is no way to add close event to the end of Ember event call chain (I don’t know any) then I think we are stuck with current solution. Unless you think that it is possible to change the way dropdown is closed right now by manipulating visibility instead not rendering content at all.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
cibernoxcommented, Jan 13, 2017

When I did something similar, I did it by yielding the dropdown API and using it inside my links.

  {{#basic-dropdown as |dropdown|}}
    {{#dropdown.trigger}}Trigger{{/dropdown.trigger}}
    {{#dropdown.content}}
      <ul class="{{dropdownMenuClass}}">
        {{yield dropdown}}
      </ul>
    {{/dropdown.content}}
  {{/basic-dropdown}}

Then where I use my wrapper:

{{#my-menu as |dropdown|}}
  <li><a href={{href-to "route.one"}} onclick={{dropdown.actions.close}}>One</a></li>
  <li><a href={{href-to "route.two"}} onclick={{dropdown.actions.close}}>Two</a></li>
{{/my-menu}}

If you want to hide this logic you can encapsulate this link in a contextual component, which is a fantastic technique:

  {{#basic-dropdown as |dropdown|}}
    {{#dropdown.trigger}}Trigger{{/dropdown.trigger}}
    {{#dropdown.content}}
      <ul class="{{dropdownMenuClass}}">
        {{yield (hash link=(component "my-menu/autoclose-link" close=dropdown.actions.close)}}
      </ul>
    {{/dropdown.content}}
  {{/basic-dropdown}}

{{! In autoclose link }}

<a href={{href-to to}} class="my-menu__link" onclick={{close}}>{{yield}}</a>

and then

{{#my-menu as |menu|}}
  <li>{{#menu.link to="route.one"}}One{{/menu.link}}</li>
  <li>{{#menu.link to="route.two"}}Two{{/menu.link}}</li>
{{/my-menu}}

I find this last approach very elegant.

0reactions
dmitry-solomadincommented, Jan 14, 2017

Thanks for the suggestion, you’re right I’ll just pass dropdown. I’ve tried Ember.run.next and Ember.schedule but it didn’t help. Anyway I don’t think it is really related to the plugin, so I’ll close the issue now, thanks for the help! However it might be good idea to add my example to the documentation you’re working on, I imagine some people would have similar problem.

Read more comments on GitHub >

github_iconTop Results From Across the Web

ember-rl-dropdown: Documentation | Openbase
closeOnChildClick may be set to a jQuery selector for child elements that should cause the dropdown to close when clicked. The default behavior...
Read more >
Ember.Templates.helpers - 3.20
Because the actionFunction is just a function, closure actions can be passed between components and still execute in the correct context. Here is...
Read more >
ember.js - How can I prevent an action on a parent component ...
EDIT: The question Stop click propagation from Ember action is very close, but the difference as I see it is that the child...
Read more >
How to avoid dropdown menu to close menu items on clicking ...
In this article, We will use stropPropagation method to prevent the dropdown menu from closing the menu list.
Read more >
48 answers on StackOverflow to the most popular Angular ...
Angular no provider for NameService; Binding select element to object in Angular ... *ngIf and *ngFor on same element causing error ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found