Artículo

Usando eventos para eliminar duplicación en controladores Angular

Tech & innovation

Usando eventos para eliminar duplicación en controladores Angular

En este post hablaremos de un controlador TracksIndexPageController que es bastante más complejo que el que habíamos enseñado en ejemplos anteriores. Este es su código tras haber usado las técnicas que describimos en los dos posts anteriores (extender con comportamiento los resources de Angular y mover lógica y estado a objetos JavaScript): [gist id="eb1ba2b163cd154c56e8"] Aunque la mayor parte de la lógica desapareció del controlador introduciendo cuatro widgets (activities, dateRange, categoryList y pagination), aún quedaba duplicación en las funciones encargadas de la coordinación entre widgets (mira las funciones: loadMonthActivities, loadWeekActivities, loadYearActivities, loadCurrentDateRangeActivities, loadNextDateRangeActivities, loadPreviousDateRangeActivities y selectCategory). Una manera de librarse de esta duplicación es usando eventos. Empezamos publicando un evento 'DateRange:Changed' usando $rootScope.$broadcast desde la función updateRange del widget dateRange. Después añadimos un listener para dicho evento en el controlador que hacía que se cargaran nuevas actividades cada vez que el evento era publicado. También añadimos algunos convenience helpers nuevos en la API de dateRange para que fuera más fácil usarlo desde el partial. Así quedó el código de TracksIndexPageController después de estos cambios: [gist id="bc177f08456c8a2cb5fa"] En él se puede observar que las funciones loadMonthActivities, loadWeekActivities, loadYearActivities, loadCurrentDateRangeActivities, loadNextDateRangeActivities y loadPreviousDateRangeActivities han desaparecido y este fragmento del código [gist id="3be7f0d9a6e7545f9f01"] que es el que se encarga de escuchar al evento 'DateRange:Changed' para recargar las activities cada vez que el rango de fechas seleccionado cambia. A continuación hicimos lo mismo con el widget categoryList y nos quedó la siguiente versión de TracksIndexPageController: [gist id="f196d9580c6f95948535"] en la cual ya no está la función selectCategory. La duplicación que señalabamos en la primera versión del controlador ya había desaparecido pero aún había un par de cosas en el código que no nos gustaban demasiado.

  1. Estabamos usando strings en diferentes partes del código para identificar los eventos (en los widgets y en el controlador). Esto era un caso de magic numbers smell.
  2. Nuestros widgets habían dejado de ser objetos JavaScript simples porque estaban usando $rootScope.$broadcast de Angular directamente. Esto los hacía un poco más difíciles de testear.

El primer problema lo resolvimos haciendo que los identificadores de los eventos se definieran en un sólo lugar de la aplicación: [gist id="ccaf51ef1b76bf9e91d6"] Para solucionar el segundo problema y conseguir un código más sencillo de testear creamos un wrapper sobre $rootScope.$broadcast de Angular: [gist id="737257acc5bfcb85391f"] Este es el fragmento de los tests del widget dateRange donde estamos usando un spy sobre eventPublisher para chequear que su método publish acaba siendo llamado siempre que se ejecuta una función que actualiza el rango de fechas: [gist id="c55773132d16a83fa24d"] Así es como quedó TrackDetailsPageController tras estos últimos cambios: [gist id="46df074acc3a9897e5ac"] En una próximo post simplificaremos aún más este controlador y su partial asociado añadiendo directivas para varios de los widgets y más comunicación por eventos. La versión original de este post se encuentra en garajeando.blogspot.com.es.

¡Hablemos!