Powiązanie metody elementu dyrektywy AngularJS - TypeError: Nie można użyć operatora „in” do wyszukania „functionName” w 1

92

To jest kontroler głównego szablonu:

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

To jest dyrektywa:

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

Oto jak dyrektywa jest stosowana w głównym szablonie:

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

a ta metoda jest wywoływana z szablonu dyrektywy (website-overview.html):

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

PYTANIE: Po kliknięciu EDYTUJ w konsoli pojawia się ten błąd:

TypeError: Nie można użyć operatora „in” do wyszukania „editWebsite” w 1

Czy ktoś wie, co tu się dzieje?

CodeVirtuoso
źródło

Odpowiedzi:

180

Ponieważ zdefiniowałeś powiązanie wyrażenia ( &), musisz jawnie wywołać je z parametrem literału obiektu zawierającym, idjeśli chcesz powiązać go w kodzie HTML jako edit-website="editWebsite(id)".

Rzeczywiście, Angular musi zrozumieć, co to idjest w kodzie HTML, a ponieważ nie jest to częścią twojego zakresu, musisz dodać to, co nazywamy „lokalnymi” do wywołania, wykonując:

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

Lub jako alternatywa:

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

Z kontrolerem / kodem łącza:

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

AngularJS zawiera wyjaśnienie tego w swojej dokumentacji; poszukaj przykładu obejmującego "close({message: 'closing for now'})"następujący adres URL:

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

floribon
źródło
7
Dziękuję za odpowiedź i wskazanie dokładnej lokalizacji w dokumentacji, było to niewiarygodnie pomocne!
Bruno Belotti
1
@floribon Wiem, że to trochę stare, ale czy masz przykład pisania na maszynie wywołania zwrotnego?
tcrite
To naprawdę przydatne, dzięki.
Anurag pareek
nadal przydatne dla osób pracujących nad starszymi projektami .. dzięki
BMWCMW
Często pożądane jest przekazywanie danych z zakresu izolowanego za pośrednictwem wyrażenia do zakresu nadrzędnego; można to zrobić, przekazując mapę lokalnych nazw zmiennych i wartości do funkcji opakowującej wyrażenie . Na przykład hideDialogfunkcja przyjmuje komunikat do wyświetlenia, gdy okno dialogowe jest ukryte. Jest to określone w dyrektywie przez wywołanie close({message: 'closing for now'}). Wtedy zmienna lokalna messagebędzie dostępna w on-closewyrażeniu. ”[podkreślenie moje] Prawda jest dziwniejsza niż fikcja. Chciałbym wiedzieć, w jaki sposób wybrali to jako najlepsze rozwiązanie dla programów obsługi zdarzeń.
ruffin
7

TL; DR; - Zakładasz, że powiązana funkcja jest przekazywana do komponentu podrzędnego. To jest niepoprawne. W rzeczywistości AngularJS analizuje szablon łańcucha i tworzy nową funkcję, która następnie wywołuje funkcję nadrzędną.

Ta funkcja musi otrzymać obiekt z kluczami i wartościami, a nie zwykłą zmienną.

Dłuższe wyjaśnienie

Dzieje się tak, gdy powiązałeś funkcję za pomocą „&” i próbowałeś wywołać tę funkcję ze swojego kontrolera, przekazując zwykłą zmienną zamiast obiektu zawierającego nazwę zwykłej zmiennej. Klucze obiektów są potrzebne silnikowi szablonów, aby dowiedzieć się, jak przekazać wartości do powiązanej funkcji.

na przykład. dzwoniłeś boundFunction('cats')raczej niżboundFunction({value: 'cats'})

Przykład praktyczny

Powiedzmy, że tworzę taki komponent:

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

Ta funkcja (w rodzicu) wygląda następująco:

onSearch(value) {
  // do search
}

W moim szablonie nadrzędnym mogę teraz zrobić to:

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

Wiązanie tutaj zostanie przeanalizowane z ciągu. W rzeczywistości nie przechodzisz tej funkcji. AngularJS tworzy dla Ciebie funkcję, która wywołuje tę funkcję. Powiązanie utworzone w szablonie może zawierać wiele rzeczy innych niż wywołanie funkcji.

AngularJS musi w jakiś sposób dowiedzieć się, skąd wziąć value, i robi to, otrzymując obiekt od rodzica.

W kontrolerze myComponent muszę zrobić coś takiego:

handleOnSearch(value) {
  if (this.onSearch) {
    this.onSearch({value: value})
  }
}
superluminium
źródło
1
Absolute moneyball; dziękuję: „ raczej zadzwoniłeś boundFunction('cats')niżboundFunction({value: 'cats'})
ruffin