Reputation: 641
I'm trying to create a collapsible accordion menu in Angular 2. At the moment my code allows the sub-menus to expand and retract using Angular 2 animations. The problem is that I need a certain sub-menu to expand when the parent is clicked on.
My current set up looks like this:
<nav>
<ul>
<li>
<span (click)="toggleSubMenu()">
List Item 1
</span>
<ul [@subMenuToggle]="subMenuState" class="sub-menu">
<li><a href="#">New</a></li>
<li><a href="#">Edit</a></li>
<li><a href="#">Remove</a></li>
</ul>
</li>
<li>
<span (click)="toggleSubMenu()">
List Item 2
</span>
<ul [@subMenuToggle]="subMenuState" class="sub-menu">
<li><a href="#">New</a></li>
<li><a href="#">Edit</a></li>
<li><a href="#">Remove</a></li>
</ul>
</li>
</ul>
</nav>
Right now when I click on one of the main menu items (List Item 1 or 2) then both sub-menus expand. (I only want the corresponding child sub-menu to expand)
My current animation trigger looks like this:
trigger('subMenuToggle',[
state('subMenuSelected', style({opacity: '1', height: '*'})),
state('subMenuDeselected', style({opacity: '0', height: '0px', overflow: 'hidden'})),
transition('subMenuSelected <=> subMenuDeselected', [
animate('150ms ease-out')
])
])
and the toggleSubMenu() method changes the state:
export class NavSidebarComponent {
subMenuState: string = 'subMenuDeselected';
toggleSubMenu() {
this.subMenuState = (this.subMenuState === 'subMenuSelected' ? 'subMenuDeselected' : 'subMenuSelected');
}
}
Is there a good way to use the toggleSubMenu() method to figure out which menu item is clicked on, then expand the corresponding sub-menu? or will I have to create a toggle method for each parent menu item separately?
Thanks
Upvotes: 3
Views: 4056
Reputation: 641
I actually couldn't figure it out using the animations without creating a method for each list item so I took a different route and decided to create a custom directive for the dropdown effect. In my dropdown directive I have:
import {Directive, HostBinding, HostListener} from '@angular/core';
@Directive({
selector: '[appDropdown]'
})
export class DropdownDirective {
@HostBinding('class.open') get opened() {
return this.isOpen;
}
@HostListener('click') open() {
this.isOpen = (this.isOpen === true ? false : true);
}
private isOpen = false;
}
This will basically track whether or not the element is true or false when clicked on and will switch between true and false every click. When true, it will add the .open
css class to the element.
After I created the directive, I imported it into my nav component:
import { DropdownDirective } from "./dropdown.directive";
Next I attached the custom dropdown directive to my element:
<nav>
<ul>
<li>
<span appDropdown>
List Item 1
</span>
<ul class="sub-menu">
<li><a href="#">New</a></li>
<li><a href="#">Edit</a></li>
<li><a href="#">Remove</a></li>
</ul>
</li>
<li>
<span appDropdown>
List Item 2
</span>
<ul class="sub-menu">
<li><a href="#">New</a></li>
<li><a href="#">Edit</a></li>
<li><a href="#">Remove</a></li>
</ul>
</li>
</ul>
</nav>
and finally I used css to do the actual dropdown animation by hiding the sub-menu <ul>
initially by making it's height: 0;
and opacity: 0;
then when the .open
class is added to the span element, I just change the sub-menu style to opacity: 1;
and height: 100%;
.sub-menu{
opacity: 0;
overflow: hidden;
height: 0;
}
.open + ul.sub-menu {
opacity: 1;
height: 100%;
}
Upvotes: 2
Reputation: 144
Can you pass an argument to toggleSubMenu()? e.g.:
<span (click)="toggleSubMenu(1)">
List Item 1
</span>
Upvotes: 0