AngularJS-Direktivenelementmethodenbindung - TypeError: Der Operator 'in' kann nicht verwendet werden, um in 1 nach 'functionName' zu suchen

90

Dies ist der Controller der Hauptvorlage:

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

Dies ist die Richtlinie:

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

So wird die Direktive in der Hauptvorlage angewendet:

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

und diese Methode wird aus der Direktivenvorlage (website-summary.html) aufgerufen:

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

FRAGE: Wenn Sie auf BEARBEITEN klicken, wird dieser Fehler in der Konsole angezeigt:

TypeError: Der Operator 'in' kann nicht verwendet werden, um in 1 nach 'editWebsite' zu suchen

Weiß jemand was hier los ist?

CodeVirtuoso
quelle

Antworten:

177

Da Sie einen Ausdruck bindend ( &) definiert haben, müssen Sie ihn explizit mit einem JSON aufrufen, der das enthält, idwenn Sie ihn im HTML als binden möchten edit-website="editWebsite(id)".

In der Tat muss Angular verstehen, was dies idin Ihrem HTML-Code ist, und da dies nicht Teil Ihres Bereichs ist, müssen Sie Ihrem Aufruf sogenannte "Einheimische" hinzufügen, indem Sie Folgendes tun:

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

Oder als Alternative:

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

Mit dem Controller / Link-Code:

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

Dies ist hier dokumentiert, suchen Sie nach dem Beispiel mit "close({message: 'closing for now'})"

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

Floribon
quelle
7
Vielen Dank für Ihre Antwort und den Hinweis auf die genaue Position in der Dokumentation. Es war unglaublich hilfreich!
Bruno Belotti
1
@floribon Ich weiß, dass dies etwas alt ist, aber haben Sie ein Beispiel für die Typisierung des Rückrufs?
Tcrite
Es ist wirklich nützlich, danke.
Anurag Pareek
immer noch nützlich für Leute, die an Legacy-Projekten arbeiten. Danke
BMWCMW
4

TL; DR; - Sie gehen davon aus, dass die gebundene Funktion an die untergeordnete Komponente übergeben wird. Das ist falsch. Tatsächlich analysiert AngularJS die Zeichenfolgenvorlage und erstellt eine neue Funktion, die dann die übergeordnete Funktion aufruft.

Diese Funktion muss ein Objekt mit Schlüsseln und Werten empfangen und keine einfache Variable.

Längere Erklärung

Dies geschieht, wenn Sie eine Funktion mit '&' gebunden und versucht haben, diese Funktion von Ihrem Controller aus aufzurufen, indem Sie eine einfache Variable anstelle eines Objekts übergeben, das den Namen der einfachen Variablen enthält. Die Objektschlüssel werden von der Template-Engine benötigt, um herauszufinden, wie Werte an die gebundene Funktion übergeben werden.

z.B. Sie haben boundFunction('cats')eher angerufen alsboundFunction({value: 'cats'})

Gearbeitetes Beispiel

Angenommen, ich erstelle eine Komponente wie folgt:

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

Diese Funktion (im übergeordneten Element) sieht folgendermaßen aus:

onSearch(value) {
  // do search
}

In meiner übergeordneten Vorlage kann ich jetzt Folgendes tun:

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

Die Bindung hier wird aus der Zeichenfolge analysiert. Sie übergeben die Funktion nicht wirklich. AngularJS erstellt für Sie eine Funktion, die die Funktion aufruft. Die in der Vorlage erstellte Bindung kann viele andere Dinge als den Funktionsaufruf enthalten.

AngularJS muss irgendwie herausfinden, woher valuees kommt, und dies geschieht, indem es ein Objekt vom übergeordneten Objekt empfängt.

In myComponent Controller muss ich Folgendes tun:

handleOnSearch(value) {
  if (this.onSearch) {
    this.onSearch({value: value})
  }
}
überleuchtet
quelle