<!DOCTYPE html>
<html>
<head>
<script data-require="angularjs@1.5.8" data-semver="1.5.8" src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="MyApp">
<section ng-controller="MainCtl">
<h1>Seleccione</h1>
<selectable-list
items="items"
ng-model="selected"
></selectable-list>
<h2>Seleccionados</h2>
<ul>
<li ng-hide="selected.length">Nadie</li>
<li ng-repeat="i in selected">{{i.name}}</li>
</ul>
</section>
</body>
</html>
angular.module("MyApp", [])
.controller("MainCtl", ["$scope", ($scope) => {
var roberto = {
id: 4,
name: "Roberto"
};
$scope.items = [{
id: 1,
name: "Juan"
}, {
id: 2,
name: "Pedro"
}, {
id: 3,
name: "Luis"
},
roberto, {
id: 5,
name: "Pablo"
}, {
id: 6,
name: "Homero"
},
];
$scope.selected = [roberto];
}])
.directive("selectableList", () => {
const template = `
<ul>
<li
ng-repeat="item in items track by item.id"
>
<input
type="checkbox"
ng-model="item.$selected"
ng-change="updateSelected()"
>
<span ng-bind="item.name"></span>
</li>
</ul>`;
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
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);
}
};
});
# 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.
Para leer mas detalles, ingresa al post original:
http://log.exodica.com.ar/3C