Liaison de méthode d'élément de directive AngularJS - TypeError: Impossible d'utiliser l'opérateur 'in' pour rechercher 'functionName' dans 1

90

C'est le contrôleur du modèle principal:

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

Voici la directive:

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

Voici comment la directive est appliquée dans le modèle principal:

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

et cette méthode est appelée à partir du modèle de directive (website-overview.html):

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

QUESTION: Lorsque vous cliquez sur EDIT, cette erreur apparaît dans la console:

TypeError: Impossible d'utiliser l'opérateur 'in' pour rechercher 'editWebsite' dans 1

Quelqu'un sait-il ce qui se passe ici?

CodeVirtuoso
la source

Réponses:

178

Puisque vous avez défini une expression binding ( &), vous devez l'appeler explicitement avec un JSON contenant le idsi vous souhaitez le lier dans le HTML en tant que edit-website="editWebsite(id)".

En effet, Angular a besoin de comprendre ce que idc'est dans votre HTML, et comme cela ne fait pas partie de votre champ d'application, vous devez ajouter ce que l'on appelle des "locaux" à votre appel en faisant:

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

Ou comme alternative:

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

Avec le code contrôleur / lien:

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

Ceci est documenté ici, regardez l'exemple impliquant "close({message: 'closing for now'})"

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

floribon
la source
7
Merci pour votre réponse et pour avoir indiqué l'emplacement précis sur la documentation, c'était incroyablement utile!
Bruno Belotti
1
@floribon Je sais que c'est un peu vieux, mais avez-vous un exemple de dactylographie du rappel?
tcrite
C'est vraiment utile, merci.
Anurag pareek du
toujours utile pour les personnes travaillant sur des projets hérités .. merci
BMWCMW
4

TL, DR; - Vous supposez que la fonction liée est passée au composant enfant. Ceci est une erreur. En fait, AngularJS analyse le modèle de chaîne et crée une nouvelle fonction, qui appelle ensuite la fonction parent.

Cette fonction doit recevoir un objet avec des clés et des valeurs, plutôt qu'une simple variable.

Explication plus longue

Cela se produit lorsque vous avez lié une fonction en utilisant '&' et que vous avez essayé d'appeler cette fonction depuis votre contrôleur, en passant une variable simple plutôt qu'un objet contenant le nom de la variable simple. Les clés d'objet sont nécessaires au moteur de création de modèles pour déterminer comment transmettre des valeurs dans la fonction liée.

par exemple. tu as appelé boundFunction('cats')plutôt queboundFunction({value: 'cats'})

Exemple travaillé

Disons que je crée un composant comme celui-ci:

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

Cette fonction (dans le parent) ressemble à ceci:

onSearch(value) {
  // do search
}

Dans mon modèle parent, je peux maintenant faire ceci:

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

La liaison ici sera analysée à partir de la chaîne. Vous ne passez pas réellement la fonction. AngularJS crée une fonction pour vous qui appelle la fonction. La liaison créée dans le modèle peut contenir de nombreux éléments autres que l'appel de fonction.

AngularJS doit en quelque sorte déterminer d'où provenir value, et il le fait en recevant un objet du parent.

Dans le contrôleur myComponent, je dois faire quelque chose comme:

handleOnSearch(value) {
  if (this.onSearch) {
    this.onSearch({value: value})
  }
}
superluminaire
la source