Retomamos este proyecto con Angular, donde estamos construyendo una recipes app, con la que podrás buscar recetas y tener un sistema que te permita apuntar tu "lista de la compra". Si acabas de aterrizar aquí, puedes ver las partes #1 y #2 antes .
En esta tercera parte vamos a crear nuestra propia directiva (en inglés, custom directive) para abrir y cerrar el menú desplegable del header y de una receta individual. Es decir, los botones Manage y Manage recipe.
menú desplegable = dropdown
Si no sabes cómo crear una custom directive, aquí tienes una guía paso a paso donde aprenderás a hacerlo.
Cómo crear una custom directive para crear menús tipo dropdowns
Recordemos que los dropdowns no funcionan porque en su día únicamente importamos el archivo CSS de Bootstrap, pero no sus archivos de JavaScript (en adelante, JS). Así lo hicimos porque es una buena práctica usar únicamente Angular para interactuar con nuestro DOM.
1. Creamos manualmente la directiva en la carpeta shared. Llamamos al archivo dropdown.directive.ts.
2. Usamos el decorador @Directive para especificar que estamos creando una directiva.
3. Dentro del decorador, creamos el selector para definir de qué forma usaremos esta directiva, que en este caso tomará la forma de un atributo HTML, así que la escribimos entre corchetes. La llamamos appDropdown.
La funcionalidad que queremos configurar consiste en añadir/quitar dinámicamente la clase de CSS llamada show, que es una clase que viene por defecto con Bootstrap. Digo "dinámicamente", porque queremos alternar la inclusión de esa clase dependiendo de si ya está incluida cuando hagamos clic en un botón o no. Para eso, deberemos crear un código que haga de event listener, "escuchando" cuando el usuario haga clic en alguno de los botones.
alternar = toggle
import { Directive } from '@angular/core'; @Directive({ selector: '[appDropdown]' }) export class DropdownDirective { }
4. Declaramos la directiva en el app.module.ts.
import { DropdownDirective } from './shared/dropdown.directive'; @NgModule({ declarations: [ ... DropdownDirective
Para entender lo que hace la clase de CSS de la que estamos hablando (show), vamos a probarla en el botón del header, sobre el <div> que contiene la clase dropdown-menu, en el archivo header.component.html. La añadimos en ese <div>.
Si guardas, podrás ver el menú desplegado de la siguiente manera:
¡Perfecto! Esto demuestra la que la clase show funciona. Pero el pequeño menú se nos sale de la pantalla, así que le añadimos la clase dropdown-menu-right.
Esto debería mostrar el menú dentro de la página, y no cortado, como antes.
5. Ya podemos quitar la clase show y dejar el <div> como estaba, porque sólo lo hemos hecho para ver cuál era el efecto al añadirla.
6. Añadimos la directiva en el botón Manage del header.
7. En la directiva, creamos una propiedad de tipo boolean llamada isOpen, en referencia al estado inicial en que queremos que esté nuestro dropdown. Como queremos que esté cerrado, isOpen debería ser false.
8. En el constructor inyectamos dos propiedades de tipo ElementRef y Renderer2. Recuerda que podemos transformarlas en propiedades de TS añadiéndoles la keyword "private" delante. Las podemos llamar eleRef y renderer, respectivamente.
El ElementRef nos da acceso a un elemento HTML
El Renderer2 nos da acceso al DOM
@Directive({ selector: '[appDropdown]' }) export class DropdownDirective { isOpen = false; constructor(private eleRef: ElementRef, private renderer: Renderer2) { } }
9. Con la ayuda del @HostListener, utilizamos un click event para capturar el acto del usuario de hacer clic sobre el menú.
10. Creamos un evento al que llamamos toggleMenu, por ejemplo, que se encargará de quitar o añadir la clase show según el usuario haga clic en el botón para mostrar el menú. Es decir, la irá alternando: si el menú no se ve, añadirá la clase show, si se ve, la quitará.
Esta comprobación la hacemos con un bloque de if / else statement.
Como lo que queremos que suceda al hacer clic es alternar el estado de la propiedad isOpen, se lo indicamos.
@HostListener('click') toggleMenu() { if (!this.isOpen) { // show the menu } else { // hide the menu } // toggle the property this.isOpen = !this.isOpen; }
Para acceder al DOM, utilizamos el renderer, que nos ofrece métodos como el addClass o el removeClass. Los parámetros para estos métodos son:
1º el elemento HTML sobre el que queremos añadir o quitar la clase
2º la clase de CSS que queremos quitar o añadir (show)
En cuanto al elemento HTML, podemos acceder a él con el eleRef, pero al que queremos acceder es a su hermano inmediato, es decir, al <div> hermano del <a>:
Porque ese es el verdadero menú desplegable. El <a> sólo contiene el botón para desplegarlo.
Al hermano inmediato del elemento podemos acceder usando nextElementSibling.
if (!this.isOpen) { // show the menu this.renderer.addClass(this.eleRef.nativeElement.nextElementSibling, 'show'); } else { // hide the menu this.renderer.removeClass(this.eleRef.nativeElement.nextElementSibling, 'show'); }
¡Y ya lo tenemos! Sólo nos queda añadir la directiva donde la necesitemos, es decir, en el botón Manage recipe, que está en el recipe-detail.component.html.
¡Perfecto!
Como toque final, podríamos hacer que el menú pudiese cerrarse al hacer clic en cualquier lugar de la página, no sólo en el botón. Para eso, podemos manipular el DOM un poquito más, así:
document.addEventListener('click', event => { if (event.target !== this.eleRef.nativeElement) { this.isOpen = false; this.renderer.removeClass(this.eleRef.nativeElement.nextElementSibling, 'show'); } }); // toggle the property this.isOpen = !this.isOpen;
¡Y ahora si que sí!
¡BRAVO!
¡Y con esto terminamos la 3ª parte de este proyecto! Espero que hayas aprendido algo nuevo . Si te queda alguna duda, ¡nos vemos en los comentarios! Y si quieres seguir aprendiendo, ¡nos vemos en la parte #4!
Sobre la autora de este post
Soy Rocío, una abogada reconvertida en programadora. Soy una apasionada de aprender cosas nuevas y ferviente defensora de que la única manera de ser feliz es alcanzando un equilibrio entre lo que te encanta hacer y lo que te saque de pobre. Mi historia completa, aquí.
Más recursos de aprendizaje
En mi experiencia, la manera más eficaz para aprender Angular es combinando varias vías de aprendizaje. Uno de mis métodos favoritos son los vídeo-cursos y mi plataforma predilecta para eso es Udemy. He hecho varios cursos pero sólo recomiendo aquellos que verdaderamente me han sido útiles. Aquí van:
Si necesitas apoyo en forma de libro, puede que éstos te sirvan de ayuda:
La programación es un mundo que evoluciona a una velocidad de vértigo. Los autores de estos libros lo saben, por eso suelen encargarse de actualizar su contenido regularmente. Asegúrate de que así sea antes de adquirirlos .
Participo en el programa de afiliados de Udemy y Amazon, lo que significa que, si compras alguno de estos cursos y/o libros, yo me llevaré una pequeña comisión y a ti no costará nada extra. Vamos, lo que se dice un win-win .
Otros artículos que pueden interesarte