Creating dropdown functionality

Let's create some drop-down functionality by using directives. You could have also chosen some components to create it, but in a few cases, directives provide more flexibility. In this chapter, I have chosen directives since drop-downs can be used in various ways. Not only can the drop-down trigger be applied to a button—it can also be applied to other elements, such as anchors.

Let's create four directives: dropdown, dropdown-toggle, dropdown-menu, and dropdown-item. The dropdown directive will be the parent directive that will control whether the drop-down is open and not, while dropdown-toggle will be used to toggle the state of the drop-down. dropdown-menu will be the parent of all dropdown-item we add. We'll also export them as they are in the library. By doing this, they will be able to be imported. We can do this by importing BulmaModule into any application.

Let's run the following commands in the Terminal to create four directives:

> ng g d dropdown/dropdown --project bulma --export
> ng g d dropdown/dropdown-toggle --project bulma --export
> ng g d dropdown/dropdown-menu --project bulma --export
> ng g d dropdown/dropdown-item --project bulma --export

Now, let's go from the top to the bottom and slowly add functionality to each one. First, let's just use the directives to add specific classes to each element.

Let's make sure that any element that has baDropdownItem directives has a class of dropdown-item:

import { Directive } from '@angular/core';

@Directive({
selector: '[baDropdownItem]',
host: {
'class': 'dropdown-item'
}
})
export class DropdownItemDirective {

constructor() { }

}

Similarly, any element that has baDropdownItem directives needs to have a class of dropdown-menu and a role of menu:

import { Directive } from '@angular/core';

@Directive({
selector: '[baDropdownMenu]',
host: {
'class': 'dropdown-menu',
'role': 'menu'
}
})
export class DropdownMenuDirective {

constructor() { }

}

Any element with baDropdownToggle will have the aria-haspopup attribute on it:

import { Directive } from '@angular/core';

@Directive({
selector: '[baDropdownToggle]',
host: {
'attr.aria-haspopup': 'true'
}
})
export class DropdownToggleDirective {

constructor() { }

}

Finally, let's add the class of dropdown and is-active to the baDropdown directive:

import { Directive } from '@angular/core';

@Directive({
selector: '[baDropdown]',
host: {
'class': 'dropdown is-active'
}
})
export class DropdownDirective {

constructor() { }
}

Now, in our demo application, we'll need to remove the dropdown, dropdown-item, and dropdown-menu classes and replace them with our new directives in the app.component.html file. Also, make sure that we remove the role from dropdown-menu, as well as the aria-haspopup attribute from the drop-down toggle button:

<div baDropdown>
<div class="dropdown-trigger">
<button class="button" baDropdownToggle aria-controls="dropdown-
menu"
<span>Dropdown button</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div baDropdownMenu id="dropdown-menu">
<div class="dropdown-content">
<a href="#" baDropdownItem>
Dropdown item
</a>
<a baDropdownItem>
Other dropdown item
</a>
<a href="#" baDropdownItem>
Another dropdown item
</a>
</div>
</div>
</div>

Now, when you check your demo application, you should see the same drop-down component and no toggling functionality. This is because we haven't touched any logic to toggle whether the drop-down is open or not.

Let's start with our parent directive, DropdownDirective. Here, we'll create the class properties menu and toggle what we will set from their respective directives by getting the host, that is, DropdownDirective. We will also create an open property and then create a get property to get the open status so that it can be used in host binding. Let's remove the is-active class from the HostBinding class and add its own HostBinding, depending on the open status:

import { Directive } from '@angular/core';
import { DropdownMenuDirective } from './dropdown-menu.directive';
import { DropdownToggleDirective } from './dropdown-toggle.directive';

@Directive({
selector: '[baDropdown]',
host: {
class: 'dropdown',
'[class.is-active]': '_open'
}
})
export class DropdownDirective {
open: boolean;
menu: DropdownMenuDirective;
toggle: DropdownToggleDirective;

get _open() {
return this.open;
}

constructor() { }

}

Now, let's use the Host decorator to get the instance of our parent directive DropdownDirective, and set the toggle property to the instance of DropdownToggleDirective. Let's add a click event to our Host object. Then, in the toggle method, toggle the DropdownDirective open property:

import { Directive, Host } from '@angular/core';
import { DropdownDirective } from './dropdown.directive';

@Directive({
selector: '[baDropdownToggle]',
host: {
...
'(click)': '_toggle($event)'
}
})
export class DropdownToggleDirective {

constructor(@Host() private dropdown: DropdownDirective) {
this.dropdown.toggle = this;
}

_toggle(event) {
this.dropdown.open = !this.dropdown.open;
}

}

Let's also set the instance of DropdownMenu in DropdownMenuDirective to the DropdownDirective class property menu. We need to make sure that, when the drop-down menu is clicked, the drop-down closes:

import { Directive, Host } from '@angular/core';
import { DropdownDirective } from './dropdown.directive'; @Directive({
selector: '[baDropdownMenu]',
host: {
class: 'dropdown-menu',
'(click)': '_close()'
}
})
export class DropdownMenuDirective {

constructor(@Host() private dropdown: DropdownDirective) {
this.dropdown.menu = this;
}

_close() {
this.dropdown.open = false;
}

}

Now, let's check our demo application. You should see that the drop-down is closed in the beginning, but when you click on drop-down button, the menu opens up. If you click on any item inside the menu or drop-down button, the menu should close.

Next, let's try to add accessibility support to our component.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.31.209