Currently in the process of developing an application using Meteor alongside Angular 2 and TypeScript.
My aim is to have the ability to click on a menu item, which will then add a class called open
to its parent element.
The method I'm using involves having a link with the class nav-dropdown-toggle
. When this link is clicked, my directive captures the event and modifies the variable _open
accordingly (the logging aspect of this functionality is working as intended).
However, there's an issue I've encountered where sometimes it functions correctly, while other times it only logs the events without actually adding or removing the specified class.
Could anyone pinpoint what might be going wrong in this scenario?
Here is the directive code snippet:
import { Directive, HostListener } from '@angular/core';
@Directive({
selector: '.nav-dropdown',
host: {
'[class.open]': '_open',
}
})
export class NavDropdownDirective {
private _open = false;
/**
* Determines if the dropdown menu is currently open.
*/
isOpen() {
console.log("Open => " + this._open);
return this._open;
}
/**
* Opens the dropdown menu.
*/
open() {
this._open = true;
}
/**
* Closes the dropdown menu .
*/
close() {
this._open = false;
}
/**
* Toggles the dropdown menu.
*/
toggle() {
if (this.isOpen()) {
this.close();
} else {
this.open();
}
console.log("toggle pushed: _open = "+ this._open);
}
}
/**
* Enables toggling of the dropdown through click interaction.
*/
@Directive({
selector: '.nav-dropdown-toggle',
})
export class NavDropdownToggleDirective{
constructor(private dropdown: NavDropdownDirective) {}
@HostListener('click', ['$event'])
toggleOpen($event:any) {
console.log($event);
$event.preventDefault();
this.dropdown.toggle();
console.log("is open? => "+this.dropdown.isOpen());
}
}
export const NAV_DROPDOWN_DIRECTIVES = [NavDropdownDirective, NavDropdownToggleDirective];
This represents my module setup:
//imports
...
import { NAV_DROPDOWN_DIRECTIVES } from './shared/nav-dropdown.directive'
@NgModule({
imports: [
...,
...
],
exports: [ RouterModule ],
declarations: [
...,
NAV_DROPDOWN_DIRECTIVES,
],
providers: [
...
],
bootstrap: [
AppComponent
]
})
export class AppModule {}
Implementation within my layout:
@Component({
selector: 'app-dashboard',
template
})
@InjectUser("user")
export class FullLayoutComponent implements OnInit {
user: Meteor.User;
constructor(private router: Router) {}
ngOnInit()
{
}
ngOnDestroy() {
this._userNotificationSub.unsubscribe();
}
}
The HTML structure:
<ul class="nav">
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" [routerLink]="['dashboard']"><i class="icon-home"></i> Dashboard </a>
</li>
<li class="nav-item nav-dropdown" routerLinkActive="open">
<a class="nav-link nav-dropdown-toggle" href="#"><i class="icon-people"></i> Employees</a>
<ul class="nav-dropdown-items">
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" [routerLink]="['employees/list']"><i class="icon-list"></i> List </a>
</li>
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" [routerLink]="['employees/new']"><i class="icon-user"></i> New </a>
</li>
</ul>
</li>
</ul>
Description of the child component:
import { Component, OnInit } from '@angular/core';
import template from './dashboard.component.html';
@Component({
selector: 'app-dashboard-children',
template
})
export class DashboardComponent implements OnInit {
constructor( ) { }
ngOnInit(){
console.log("Dashboard");
}
}
Routing information:
export const routes: Route[] = [
{path: '', component: LoginComponent, data: {title: 'Login'}, pathMatch: 'full'},
{
path: 'app', component: FullLayoutComponent, data: {title: 'Home'}, canActivate: [AuthGuard],
children: [
{path: 'dashboard', component: DashboardComponent, data: {title: 'Dashboard'}},
{
path: 'employees', component: EmployeesComponent, data: {title: 'Employees'},
children: [
{path: '', redirectTo: 'list', pathMatch: 'full'},
{path: 'list', component: EmployeesListComponent, data: {title: 'Listado'}},
{path: 'new', component: EmployeeNewComponent, data: {title: 'New'}},
{path: 'edit/:id', component: EmployeeEditComponent, data: {title: 'Edit'}},
]
}
]
},
{path: '**', component: Error404Component, data: {title: 'Error'}}
];