Cómo usar ngModel y formularios con WebComponents en Angular

Pablo Ortuño
DotTech
Published in
4 min readMar 24, 2020

Los WebComponets son una herramienta tremendamente útil y que nos va a permitir cambiar nuestros métodos de trabajo no teniendo que depender de un framework concreto para el desarrollo de herramientas y funcionalidades.

Pero a pesar de la facilidad que tiene para integrarse con nuestros sistemas o nuestros frameworks a veces necesitamos darle algunas instrucciones para que el framework y el WebComponent sean capaces de entenderse en todo su potencial.

En este caso vamos a hablar de esos WebComponent que queremos usar en formularios o que queremos hacer uso de la directiva ngModel o formControl, hablamos de elementos que almacenan una variable resultado: custom inputs, selectores, elementos de selección de calendario o cualquier tipo de elemento que al final se comporta como un elemento que almacena un valor y cambia en funciona de una acción del usuario.

Para entender cómo hacer uso de la directiva ngModel o formControl en nuestros WebComponent es necesario entender cómo angular lo usa con una etiqueta <input> o <textarea> por ejemplo.

Si nos vamos a https://www.w3schools.com/tags/tag_input.asp veremos que una de las propiedades comunes que tiene estos elementos es el atributo

  • value como propiedad que almacena el valor
  • onChange como evento de salida que indica un cambio en la propiedad value

Estos dos elementos son comunes entre todos los elementos html de formularios, parece obvio por tanto que nuestro WebComponent debe tener estos dos elementos para poder entenderse con nuestro querido Angular.

Cómo funciona Angular

Las directivas [ngModel],[formControl] y [formControlName] usan el modo por defecto de angular a la hora de decidir la lógica de acceso a los elementos.

Esta información la podemos ver en la implementación de la directiva DefaulValueAccesor:

https://github.com/angular/angular/blob/9.1.x/packages/forms/src/directives/default_value_accessor.ts#L47

Si analizamos este archivo encontramos dos partes:

Aquí podemos ver sobre que elementos actuara esta directiva, en este caso por defecto, Angular permite usar ngModel sobre los elementos nativos:

  • Input
  • TextArea

Por otro lado, podemos ver la lógica que usaría Angular para escribir en el elemento, leer un cambio en el valor, o detectar que se ha interactuado con él.

Podemos ver que efectivamente usa la propiedad value como punto sobre el cual escribir y el evento onChange como elemento al que Angular escuchara para saber que se ha producido un cambio.

Partiendo de estas premisas y sin olvidar la existencia de esta directiva de Angular vamos a ver cómo usarlo en nuestros WebComponent.

Cómo permitir a nuestros WebComponent hacer uso de ngModel o formControl

Existen dos formas de habilitar el uso de ngModel y formControl a nuestros WebComponents. La primera y siempre que hayamos implementado nuestro componente siguiendo el estándar de uso de los elementos tipo input, es decir con una propiedad value y un evento de salida onChange, seria decirle a Angular que para ese elemento use el sistema por defecto.

Para ello haríamos lo siguiente:

Si recordamos en el campo selector del archivo por defecto de angular indicaba lo siguiente:

El ultimo parámetro es la clave, [ngDefaultControl], esto implica que cualquier elemento al cual le añadamos esta directiva y contenga un ngModel usara esta configuración, es decir que podremos hacer lo siguiente:

Añadiendo esta directiva y siempre que nuestro componente mantenga el formato value, onChange funcionara sin problemas con ngModel.

Pero obviamente no es muy deseado añadir ngDefaultControl a todos nuestros webcomponents o simplemente hemos decidido usar unas variables internas distintas al estándar usado en Angular. Para solucionar esto podemos definir nuestra propia directiva ControlValueAccessor.ts

Usando ngModel y formControl en todo su potencial

Como hemos comentado podemos hacer que nuestros WebComponent hagan uso de ngModel o formControl sin necesidad de indicarle a Angular el modo por defecto o sin necesidad de implementar el sistema value, onChange. Para ello vamos a definir nuestro propio ControlValueAccesor.ts haciendo uso del archivo original ControlValueAccessor de angular.

En el archivo anterior se encarga, haciendo uso de ControlValueAccesor , de indicar a angular, para los componentes indicados en el selector, cuál debe ser el comportamiento para registrar cambios o escribir en el elemento.

Como se puede apreciar, se indica desde el uso de la variable value, hasta cuál debe ser los eventos de salida para detectar un cambio, o un estado de focus o blur.

Solo nos quedaría añadir al array declarations del módulo en el que queramos hacer uso de esta configuración y ya podremos usar nuestros componentes de forma normal.

Por supuesto este sistema funciona exactamente igual para los formularios de angular, de esta forma podremos usar sin problemas los ReactiveForms de angular con todas sus propiedades como dirty o touched y el acceso a los valores de los elementos.

Algunas recomendaciones

Para no tener que escribir un archivo por cada WebComponent es recomendable que todos nuestros WebComponents sigan una lógica similar, en la que hay una propiedad interna que se actualiza por el usuario y se presenta hacia el exterior, usar value como propiedad y onChange como evento de salida, asimismo en el caso del archivo anterior los componentes usan onBlur y onFocus para emitir los estados de blur y focus.

Gracias por leer, este es mi primer post, si te ha gustado o crees que se podría mejorar, pónmelo en los comentarios =)

--

--

Pablo Ortuño
DotTech
Writer for

Entrepreneur, software developer. My passion, create great products and bring value with technology. Founder at #Trampoline #BuscoExtra, tech lead at #Soluble