How to create your own ‘two way data-binding’ using only JavaScript Pt. 3
05 Crear la estructura de entidades:
Entramos a la última parte del ejercicio, lo que sigue es crear la forma de actualizar el modelo si la vista cambia, una vez hecho esto, ya se lograría tener un personalizado ‘two way data-binding’.
Para seguir en pro de utilizar conceptos avanzados de JavaScript, lo siguiente es tener un API de entidades. Significa que las entidades específicas van a tener una plantilla de creación y además estarán acogidas a una interfaz parcial con métodos específicos.
El concepto se llama ‘Object linked’ y permite crear referencias de objetos en base a objetos padre. Heredando por consiguiente, el acceso a los métodos públicos del padre. Esto contribuye al estándar de las entidades y permite tener una estructura específica en la creación de modelos.
5.1 API de entidades
Vamos a ir bien despacio en este punto. Primero que todo se debe crear el módulo.
El objetivo es tener una plantilla de entidades y es por eso que se crea un módulo. Qué tienen normalmente las entidades? Atributos y Métodos. Por tanto la plantilla debe proveer una forma estándar para agregar atributos a un objeto y además métodos de instancia de acceso público.
5.1.1 Definir propiedades: Dentro del módulo, lo primero es crear una función que permita a las entidades crear los atributos de forma estándar.
La función ‘defineProperties’ define una forma específica de crear atributos dentro de una entidad. Los parámetros son; el objeto (entidad), una llave (nombre del atributo) y un valor (valor del atributo).
5.1.2 Crear la entidad ‘Country’: Una vez creada la función para definir atributos en el API de entidades, lo siguiente es crear la entidad ‘country’ y las respectivas propiedades.
En esta definición de entidad hay que tener en cuenta dos aspectos importantes; los parámetros.
El primer parámetro ‘vm’ será la instancia de un objeto al cual se le agregarán las propiedades de la entidad. Pero, porque una instancia de un objeto plantilla es el que tiene las propiedades de la entidad? la respuesta es por que dicha plantilla tendrá la responsabilidad de actualizar el modelo, respecto a la vista. En este punto es muy posible que se sienta un poco perdido, pero tranquilo cada vez, se ve más luz.
El segundo parámetro ‘def’ es un delegado de la función ‘defineProperties’, recuerda? la que se creó en el API de entidades.
Entonces, para poder usar la definición de la entidad que se acaba de crear, es necesario pasar los parámetros desde algún lado. Y más importante crear el objeto ‘vm’ quien finalmente crea una relación entre la vista y el modelo.
5.1.3 Crear la función para enlazar la vista y el modelo: Esta función, específicamente aplica ‘reflection’ a una entidad y setea u obtiene los valores de la vista, para luego actualizar el modelo.
Se creó un sub-módulo ‘domObjects’ el cual expone dos métodos públicos.
El primer método ‘buildModel’ es el que tendrá la tarea de llenar la instancia de la entidad con los valores de la vista. Es decir obtiene los datos escritos por el usuario en la vista y llena el modelo.
El segundo método ‘disposeModel’ tendrá la responsabilidad de limpiar el modelo. Por consiguiente la vista deberá quedar limpia también.
Podemos observar que ambos métodos llaman la misma función ‘reflectInstance’ y ambos deberían pasar un delegado que se ejecuta en dicho método ‘reflectInstance’. Esto quiere decir que la única diferencia entre ambos es que uno obtiene los valores de la vista y el otro los setea.
5.1.4 Crear los métodos en el API de entidades, para obtener o setear la vista: Hasta ahora en el API de entidades, los métodos ‘buildModel’ y ‘disposeModel’ no tienen diferencia alguna. Lo siguiente es darles funcionalidad a dichos métodos.
Se puede observar que se crearon dos métodos ‘getInputValue’ y ‘setInputValue’ tanto para establecer como para obtener el valor de los controles de tipo input. Cada método se pasa como parámetro a la función ‘feflectInstance’.
5.1.5 Crear la instancia de la entidad desde el API de entidades: Recuerde que una de las tareas era utilizar la definición de la entidad ‘CountryDefinition’ para pasar los delegados de definición de propiedades y el objeto que interactua con el modelo y la vista.
Por esta razón en el API de entidades, vamos a crear una función pública que devuelva una definición de entidad ‘CountryDefinition’. Al final del archivo ‘API de entidades’ se debe agregar lo siguiente.
En este punto ya somos capaces de devolver una ‘instancia’ por decirlo así de la entidad ‘‘Country’’. En realidad lo que se está haciendo es agregarle las propiedades. Pero como dije antes en este mismo ejercicio, las entidades se componen de propiedades y métodos. Por tanto lo siguiente es implementar funcionalidad a la entidad ‘CountryDefinition’.
A la definición de entidad ‘Country’ que previamente se había creado, lo siguiente es darle funcionalidad. Ya que tenemos una plantilla de entidades, debemos usar dichos métodos expuestos, sobre-escribiendolos por decirlo así, al enviarle una definición de la entidad.
Es decir que para este caso this es una instancia del objeto ‘domObjects’ personalizada como entidad Country. Se le agregaron las propiedades específicas de la entidad y se ‘sobre-escribe’ los métodos de la plantilla; ‘buildModel’ y ‘destroyModel’.
El usar nuevos métodos dentro de la definición de entidad, para llamar los métodos heredados por la plantilla, nos da grandes beneficios como aportar mayor funcionalidad sin perder la lógica base y de forma segura. Open-Closed principle.
5.2 Centralizar el repositorio de entidades: Como lo que queremos es mantener organizado en forma jerárquica y centralizada la creación de entidades, es necesario tener un módulo general donde se pueda acceder a dichas entidades de forma sencilla y sus respectivos métodos. esto facilita el trabajo para el ‘two way data-binding’ y le quita responsabilidades al controlador. Veamoslo en acción.
En este módulo usted puede observar que el método ‘Country’ tiene dos métodos públicos ‘get’ y ‘dispose’, respectivamente el primero crea una instancia de la definición de entidad ‘Country’ con el API de entidades y luego invoca el método ‘getModel’.
Es decir que ya tenemos la capacidad de crear una instancia de una entidad ‘Model’ a partir de los datos obtenidos en la vista ‘View’. Por otro lado el método ‘dispose’ utiliza la instancia de la entidad e invoca el método ‘destroyModel’ el cual limpia el modelo y por consiguiente la vista.
Hasta aquí si todavía está conmigo ya se puede decir que tenemos un esquema propio del concepto ‘two way data-binding’. Lo siguiente es implementarlo en el controlador y claro debemos crear el formulario HTML para agregar nuevos países.
5.3 Crear el formulario para agregar países: Ya casi acabamos el ejercicio, como ya existe la forma de enlazar el modelo con la vista, es necesario crear la vista que especifique el modelo.
En este formulario se debe tener en cuenta especialmente que las cajas de texto tienen la propiedad ‘name’ igual que el nombre de las propiedades de la entidad. Así es que el API de entidades puede localizar el control haciendo reflection de la entidad (Modelo).
5.4 Actualizar el controlador para darle responsabilidades de acceso y presentación: Lo último es modificar el controlador para que utilice el servicio de países para agregar un nuevo país. Además de paso darle funcionalidad para que controle los eventos del formulario de creación de países.
Al controlador se le agregaron varias cosas importantes; la primera es el sub-modulo ‘click’ el cual condensa todos los eventos ‘click ’ de la página. Uno para cerrar el formulario de países y el otro para agregar un nuevo país.
El botón agregar país, obtiene una instancia de la entidad ‘Country’ desde el repositorio de entidades, luego invoca el método ‘addRow’ y le envía la instancia llena de la entidad llamando el método ‘get’. Finalmente utiliza la misma instancia de la entidad ‘Country’ para destruir el modelo y actualizar la vista.
Aquí puede ver la versión completamente funcional del ejercicio.
Conclusión: Este es un buen ejemplo de como crear el tan afamado ‘two way data-binding’. Creamos una interacción personalizada entre la vista y el modelo y viceversa. Utilizamos conceptos avanzados de JavaScript, prototipos de herencia, programación orientada a objetos, entidades, entre otras cosas como promesas. Obviamente si le gustó el ejemplo puede seguir extendiéndolo y dándole funcionalidad para tener un ‘framework’ de JavaScript. O crear su propia arquitectura, para facilitarle la vida a los desarrolladores o simplemente por investigación.
Gracias por seguir todo el ejercicio y si quiere preguntar algo o criticar algo, con confianza. Lo importante es seguir creciendo como profesionales :) …