Enlace de método de elemento de directiva AngularJS - TypeError: no se puede usar el operador 'in' para buscar 'functionName' en 1

90

Este es el controlador de la plantilla principal:

app.controller('OverviewCtrl', ['$scope', '$location', '$routeParams', 'websiteService', 'helperService', function($scope, $location, $routeParams, websiteService, helperService) {
    ...     
    $scope.editWebsite = function(id) {
        $location.path('/websites/edit/' + id);
    };
}]);

Esta es la directiva:

app.directive('wdaWebsitesOverview', function() {
    return {
        restrict: 'E',
        scope: {
            heading: '=',
            websites: '=',
            editWebsite: '&'
        },
        templateUrl: 'views/websites-overview.html'
    }
});

Así es como se aplica la directiva en la plantilla principal:

<wda-websites-overview heading="'All websites'" websites="websites" edit-website="editWebsite(id)"></wda-websites-overview>

y este método se llama desde la plantilla de directiva (website-overview.html):

<td data-ng-click="editWebsite(website.id)">EDIT</td>

PREGUNTA: Cuando se hace clic en EDITAR, aparece este error en la consola:

TypeError: No se puede usar el operador 'in' para buscar 'editWebsite' en 1

¿Alguien sabe lo que pasa aquí?

CodeVirtuoso
fuente

Respuestas:

178

Dado que definió un enlace de expresión ( &), debe llamarlo explícitamente con un JSON que contenga el idsi desea vincularlo en el HTML como edit-website="editWebsite(id)".

De hecho, Angular necesita comprender qué ides esto en su HTML, y dado que no es parte de su alcance, debe agregar lo que se llaman "locales" a su llamada haciendo:

data-ng-click="editWebsite({id: website.id})"

O como alternativa:

data-ng-click="onClick(website.id)"

Con el controlador / código de enlace:

$scope.onClick = function(id) {
  // Ad "id" to the locals of "editWebsite" 
  $scope.editWebsite({id: id});
}

Esto está documentado aquí, busque el ejemplo que involucra "close({message: 'closing for now'})"

https://docs.angularjs.org/guide/directive

floribon
fuente
7
Gracias por su respuesta y por señalar la ubicación precisa en la documentación, ¡fue increíblemente útil!
Bruno Belotti
1
@floribon Sé que esto es un poco viejo, pero ¿tiene un ejemplo de mecanografiar la devolución de llamada?
tcrite
Es realmente útil, gracias.
Anurag pareek
sigue siendo útil para las personas que trabajan en proyectos heredados ... gracias
BMWCMW
4

TL; DR;- Está asumiendo que la función vinculada se está pasando al componente hijo. Esto es incorrecto. De hecho, AngularJS está analizando la plantilla de cadena y creando una nueva función, que luego llama a la función principal.

Esta función necesita recibir un objeto con claves y valores, en lugar de una variable simple.

Explicación más larga

Esto sucede cuando ha enlazado una función usando '&', y ha intentado llamar a esa función desde su controlador, pasando una variable simple en lugar de un objeto que contiene el nombre de la variable simple. El motor de plantillas necesita las claves de objeto para averiguar cómo pasar valores a la función vinculada.

p.ej. has llamado en boundFunction('cats')lugar deboundFunction({value: 'cats'})

Ejemplo resuelto

Digamos que creo un componente como este:

const MyComponent = {
  bindings: {
    onSearch: '&'
  },
  controller: controller
};

Esta función (en el padre) se ve así:

onSearch(value) {
  // do search
}

En mi plantilla principal, ahora puedo hacer esto:

<my-component on-search="onSearch(value)"></my-component>

El enlace aquí se analizará a partir de la cadena. En realidad, no está pasando la función. AngularJS está creando una función para usted que llama a la función. El enlace creado en la plantilla puede contener muchas cosas además de la llamada a la función.

AngularJS de alguna manera necesita averiguar de dónde ir value, y lo hace recibiendo un objeto del padre.

En el controlador myComponent, necesito hacer algo como:

handleOnSearch(value) {
  if (this.onSearch) {
    this.onSearch({value: value})
  }
}
superluminario
fuente