# Creando una directiva en Angular que soporte ```ng-model``` Esto es simple, pero buscando en internet me di cuenta que la documentación que hay es mala, y en español sobretodo, inexistente. Lo que vamos a hacer es crear una directiva de angular que soporte manejar un modelo con ```ng-model```, lo que me sorprende de esto es que buscando el primer resultado es una pregunta en StackOverflow llamada; [Create a directive that uses ng-model](https://stackoverflow.com/questions/14115701/angularjs-create-a-directive-that-uses-ng-model) donde la respuesta ganadora tiene 172 votos, pero personalmente diserto de esta respuesta, ya que no considero que conteste a la pregunta. ¿Por qué no usar esa respuesta? Porque queremos tener las ventajas de usar ```ng-models```, como el poder validarlo dentro de un formulario. En mi caso en particular, tuve que hacer un listado dentro de un formulario, en el que cada item puede ser seleccionado y esto afecta a los que se va a enviar al final. No voy a entrar en detalle de como funciona esto, así que solo me centraré en mostrar como definir el modelo. Lo primero es modificar nuestra directiva para requerir el [```NgModelController```](https://docs.angularjs.org/api/ng/type/ngModel.NgModelController#!): angular.module("MyApp", []) .directive("selectableList", () => { const template = ` `; return { strict: "EA", replace: true, template: template, require: '?ngModel', scope: { items: "=", }, link (scope, el, attrs, ngModel) { // scope.items es definida por el usuario y // ngModel es una instancia de ngModelController o null } }; }); Ahora hay que tener en cuenta, ```ngModel``` está requerido como opcional, por lo que puede ser ```null```. Otra cosa a tener en cuenta, es que inicialmente ```ngModel.$modelValue``` y ```ngModel.$viewValue``` nos puede venir con el valor ```NaN```, para solucionar esto vamos a incluir un iniciador (algo que saqué de [acá](https://stackoverflow.com/questions/16383767/model-modelvalue-is-nan-in-directive#25448464)). En fin dentro de la función link: var unregisterInit, selectedItems = []; // Cada vez que se seleccione o des-seleccione un // elemento, actualizamos el modelo scope.updateSelected = function(noDirty = false) { // Filtramos solo los items seleccionados selectedItems = scope.items.filter(i => i.$selected); if (ngModel) { ngModel.$setViewValue(selectedItems) // Si no se nos indica lo contrario, marcamos el // modelo como $dirty y $touched, esto es para // implemnetar con formularios if (!noDirty) { ngModel.$setDirty(); ngModel.$setTouched(); } } }; const init = function(value) { // Nos des-suscribimos del primer $watch unregisterInit(); // Si tenemos ngModel, le definimos el valor de los elementos // Seleccionados if (ngModel) { selectedItems = value.map((i) => { i.$selected = true; return i; }); ngModel.$setViewValue(selectedItems); } // En caso de que se actualice "items", actualizamos el modelo scope.$watchCollection("items", () => { scope.updateSelected(true); }); // Nullify value = null; }; // Nos subscribimos al primer cambio del scope unregisterInit = scope.$watch(() => { var value; // Si tenemos ngModel, tomamos su valor if (ngModel) { value = ngModel.$modelValue; } // Si no lo definimos antes, o es null, lo definimos // como un array vacío if (!value) { value = []; } // Se lo mandamos a init() return value; }, init); Ahora tenemos nuestra directiva de un listado de elementos seleccionables los cuales podemos usar: El cual funcionará dentro de un formulario como cualquier campo mas, por ejemplo, podemos hacer que sea requrido: Puede ver un ejemplo funcionando acá: http://embed.plnkr.co/sUKn485fPQrcDO2Q4Z51/