Archivo de la etiqueta: Angularjs

Un parámetro de la directiva de AngularJS tiene valor undefined

[programación]

Estaba modificando una directiva de un tercero y me estaba volviendo loco con un valor que siempre estaba undefined. La directiva era sencilla y no entendía cual era el error.

La definición del scope dentro de la directiva es esta:

scope: {
  searchParam: '=ngModel',
  suggestions: '=data',
  onType: '=onType',
  formId: '=formId',
  onSelect: '=onSelect',
  autocompleteRequired: '='
}

Y el uso de la directiva es este:

<autocomplete
    ng-model="vm.sCompanyName"
    data="vm.aInsuranceCompanies"
    form-id="bikeInsuranceAlert"
    on-type="vm.autocompleteChange">
</autocomplete>

El valor que me interesa obtener es el formId. ¿Veis el error? Es sutil…

form-id="'bikeInsuranceAlert'"

Faltaban unas comillas simples dentro de las dobles para obtener el valor del ID como una cadena. Lo que AngularJS estaba interpretando es que quería obtener el valor de una variable llamada bikeInsuranceAlert dentro del scope. Evidentemente esta variable no existe, y el valor asignado era undefined.

Que traicionero es AngularJS en ocasiones…

Comprobar si existe un elemento con AngularJS y ejecutar una función solo si existe

[programación]

Esta es la situación: Queremos ejecutar un plugin de JQuery sobre un elemento que se crea dinámicamente con un ng-repeat dentro una plantilla de AngularJS. Es decir, no podemos inicializar el plugin hasta que se ha cargado la plantilla y se han creado los elementos.

Tenemos un controlador específico para dicha plantilla, por lo que realizando la comprobación aquí, solucionamos la primera parte del problema. Investigando un poco, veo que la solución más popular es asignar una directiva al ng-repeat, que detectará cuando se ejecute la última iteración y lanzará un evento para ser recogido por el controlador, y entonces ya podríamos ahí ejecutar el plugin.

En Stackoverflow tenemos un ejemplo de esta aproximación, y en Nodewiz.biz tenemos otro ejemplo muy similar.

El caso es que esta aproximación me parece tremendamente rebuscada, aunque no dudo que cumple con el espíritu de AngularJS. Mi aproximación es más sencilla, aunque sospecho que no es del todo correcta, y me gustaría mejorarla con el tiempo:

$scope.bTooltipsterExists = false;

$scope.$watch(
function(){
    if(angular.element('.tooltipster').length){
        $scope.bTooltipsterExists = true;
        return true;
    }

    return false;
},
function(){
    if($scope.bTooltipsterExists){
        $(".tooltipster").tooltipster({
            trigger: 'click',
            delay: 0
        });
    }
});

Básicamente tengo un $watch que lo que hace es observar una función. Esta función busca los elementos que se crearán con el ng-repeat y tendrán la clase .tooltipster. La segunda función es la que se ejecuta cuando hay un cambio en el valor devuelto por la primera función. Es decir, cuando la primera función pase de devolver false a devolver true, se ejecutará el plugin.

Añado una segunda comprobación con la variable $scope.bTooltipsterExists porque la primera vez que se ejecuta el $watch, como no tiene una variable de referencia anterior, siempre se ejecuta la segunda función, y con esto lo evitamos.