web-dev-qa-db-fra.com

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

C'est le contrôleur du template 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 depuis le modèle de directive (website-overview.html):

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

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

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

Est-ce que quelqu'un sait ce qui se passe ici?

84
CodeVirtuoso

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

En effet, Angular besoin de comprendre ce que ce id est dans votre code HTML, et comme il ne fait pas partie de votre champ d'application, vous devez ajouter ce que l'on appelle des "locaux". appeler 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, recherchez l'exemple impliquant "close({message: 'closing for now'})"

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

171
floribon

TL; DR; - Vous supposez que la fonction liée est transmise 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 à l'aide de '&' et que vous avez essayé d'appeler cette fonction à partir de votre contrôleur, en transmettant une variable simple plutôt qu'un objet contenant le nom de la variable simple. Le moteur de modélisation a besoin des clés d’objet pour savoir comment passer des valeurs à la fonction liée.

par exemple. vous avez appelé boundFunction('cats') plutôt que boundFunction({value: 'cats'})

Exemple travaillé

Dites 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 pour vous une fonction qui appelle la fonction. La liaison créée dans le modèle peut contenir plein d'autres éléments que l'appel de la fonction.

AngularJS a en quelque sorte besoin de savoir où obtenir value, et il le fait en recevant un objet du parent.

Dans le contrôleur myComponent, j'ai besoin de faire quelque chose comme:

handleOnSearch(value) {
  if (this.onSearch) {
    this.onSearch({value: value})
  }
}
1
superluminary