Well, if you're using Angular-Bootstrap anyway, you can easily use the accordion module. If you're looking for a way to extend the existing dropdown module you'll probably not going to need my solution. It might be some more lines of code than you might expect but note that the structure is basically the implementation of a tree view, so feel free to even use it for this.
--- Note in advance:
I'm going to propose a general idea which will be derived from a tree view I implemented recently. Note that the code will give you a good idea of how to implement the functionality you want to achieve. Copy paste should work, but no guarantee. If you want to deeply understand it you should read the whole code anyway.
---
In order to use the code I'm going to propose you would need some basic structure indicating your navigation structure. Some simple json or ts object should do the job. I'd think about a structure like this:
structure = [
{
title: "foo",
link: "/foo",
children: [
{
title: "bar",
link: "/bar",
children: []
}
]
},
{
title: "baz",
link: "/baz",
children: []
}
];
You should get the idea. This will give you an easy to change and implement base structure upon which you just have to alter details in the object in order to change the structure. Put this in the parent component where you want to render your navigation. You could do it different, but I like the idea of using angulars potential and make the code very generic. If you're a programmer you'll understand the need of having an easy to use interface which basically does everything by itself.
To display the structure you'll furthermore need a TreeViewComponent, which could have the following Markup:
<ul class="tree-root-list">
<app-tree-node *ngFor="let item of structure"
[current]="item">
</app-tree-node>
</ul>
As you should have recognised, there is another component you'll need in order to display your dropdown tree navigation menu thingy. The TreeNodeComponent which should have the following(ish) markup:
<li class="node-item">
// this function will trigger the final action triggered when a node is selected
// if there are subnodes open the list, else link to the respective page, route, etc..
<p #title (click)="nodeSelected()">
<span class="icon-container">
<span>
//optional icon
</span>
</span>
<span class="node-title">
// optional text
{{title}}
</span>
</p>
<ul class="child-list"
*ngIf="hasChildElements()"
[collapse]="children_collapsed"
(collapsed)="collapsed($event)"
(expanded)="expanded($event)">
// thats the part the structure object comes in handy,
// since you don't need to add several node tags
// you'll just need to add or remove elements in the structure
// variable
<app-tree-node *ngFor="let child of current.children"
[current]="child">
</app-tree-node>
</ul>
</li>
This is some basic code for the TreeNodeComponent. Just adjust this to your needs in order to make it work. The general functionality you wanted to have shoud be covered by this.
@Component({
selector : 'app-tree-node',
templateUrl: './tree-node.component.html',
styleUrls : ['tree-node.component.scss']
})
export class TreeNodeComponent implements OnInit {
// inputs
@Input() current: any;
@Input() is_root: boolean;
// ...
// public members
public children_collapsed = true;
// view nodes
// can be useful when you want to highlight certain nodes depending on specific actions
// though not a requirement for the main task
@ViewChildren(TreeNodeComponent) child_nodes: QueryList<TreeNodeComponent>;
/**
* c'tor ...
*/
/**
* click event when node is selected
*/
public nodeSelected(): void {
// if there are child elements
if (this.hasChildElements()) {
// change collapsed state
this.children_collapsed = !this.children_collapsed;
} else {
// probably route to somewhere, do whatever you want to do with no children present here
}
}
/**
* check whether there are children
*/
public hasChildElements(): boolean {
return this.current.hasOwnProperty("children");
}
/**
* fires if div is collapsed
* @param event
*/
public collapsed(event: any): void {
// change icon
// needed this to give a visual feedback whether the folder is opened or closed
if (this.hasChildElements()) {
this.folder_icon.nativeElement.className = "glyphicon glyphicon-folder-close";
}
}
/**
* fires if div is expanded
* @param event
*/
public expanded(event: any): void {
if (this.hasChildElements()) {
this.folder_icon.nativeElement.className = "glyphicon glyphicon-folder-open";
}
}
}
I'm not going to give you the stylesheets cause that would first of be a total overkill, second css is weird and everyone has a different solution.
I'm sure you'll figure out how to style the components appropriately.
Again there is no guarantee that the proposed code will work after a copy and paste. The original project grew massive with a lot of different tree functionality you wouldn't need in your usecase. So there is the possibility of some variables which you're not going to need.
Cheers, and have fun using it.