Handling “Click Away” Functionality in Ember

Accordion Menu’s as they were before the Web

Recently, as I was working on my personal website, I came across an interesting problem. I wished to have a responsive website that when resized to a certain width the nav bar would change to an accordion style menu, as illustrated below.

Accordon Menu’s as they appear now.

I had been creating my project with EmberJS, a powerful front-end MVC framework that has been pretty fun to use. It was easy to get the hang of and start developing this new project. Ember has a lot of things going for it, but the most important aspect I would say is speed. Fast loading pages = happy website viewers, and ember certainly accomplishes that task.

Now onto my issue, after getting my accordion menu to slide down, I needed it to slide back up. It was relatively easy to get working with the button itself, I just assigned an action: toggleSidebarCollapse() to the button and wrote this code in my application.js controller.

/app/controllers/application.js
export default Ember.Controller.extend({
sideSidebarCollapse: false,
  actions: {
toggleSidebarCollapse() {
var x = $("#custom-collapse")
      if ( !this.get('sideSidebarCollapse') ){
x.slideDown();
this.toggleProperty('sideSidebarCollapse');
        Ember.run.next(this,function(){
var _this = this;
          $(document).one('click',function() {
_this.toggleProperty('sideSidebarCollapse');
x.slideUp();
});
});
}
}
}
});

This code sets a variable: sideSidebarCollapse and sets it to false, stating that the sidebar by default should be collapsed. Then whenever the action toggleSidebarCollapse is called, we check if it is collapsed and if so, call the slideDown() method on the accordion menu. This creates a nice visual of the menu appearing.

However we still need to handle closing the menu. In my case I wanted it to close whenever the user clicked anywhere that was not on the menu. To accomplish this, I start an Ember.run.next call. This starts a separate loop which will run after control has been given back to the system (~1ms). This ensures the inner code won’t be handled in the same context as the action. If I did not call the Ember.run.next function, my ‘click’ event would still be registering from when I clicked the button, causing the inner code to execute and my accordion to open and shut immediately after.

As for the next section of code, I call $(document).one, signifying that the ‘click’ event is going to only occur one time. The event handler itself just calls slideUp() and toggles the sideSidebarCollapse variable we set before, however it is called whenever the user clicks anywhere on the document. This works to my benefit, as I want the menu to close in all cases, even when clicking on pages within the menu itself.

The end result can be found below, play around with the screen resizing and the menu!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.