9

Aktualizacja: To musiało być coś głupiego w innej części kodu. Działa teraz, więc składnia bindToController jest w porządku.Dyrektywy AngularJS 1.4: zakres, wiązanie dwukierunkowe i bindToController

Używamy AngularJS 1.4, który wprowadził new way to use bindToController w dyrektywach.

Po sporo czytania (i być może nie rozumiejąc wszystkiego), określiliśmy nasze dyrektywa tak:

.directive('mdAddress', function mdAddress() { 
    var directive = { 
     restrict: 'EA', 
     scope: {}, 
     bindToController: { 
     address: '=' 
     }, 
     templateUrl: 'modules/address/address.html', 
     controller: AddressController, 
     controllerAs: 'dir' 
    }; 

wywołanie go z innego widoku jak ten:

<md-address address="vm.address"></md-address> 

Będąc wcześniej zdefiniowany w kontrolce widoku:

vm.address = { 
    street: null, 
    countryCode: null, 
    cityCode: null, 
    postalCode: null 
    }; 

Odwoływanie się do zmiennych w Przykładowy szablon dyrektywy:

<md-input-container> 
    <label>{{'ADDRESSNUMBER' | translate}}</label> 
    <input type="number" ng-model="dir.address.streetNumber"> 
    </md-input-container> 

Spędziliśmy 4 godziny próbując ustalić, dlaczego nasza dyrektywa nie działa. Cóż, działało, ale dwukierunkowe powiązanie między kontrolerem a dyrektywą nie było, vm.address.street było beznadziejnie ustawione na zero.

Po pewnym czasie, po prostu starał stary sposób:

.directive('mdAddress', function mdAddress() { 
    var directive = { 
     restrict: 'EA', 
     scope: { 
     address: '=' 
     }, 
     bindToController: true, 
     templateUrl: 'modules/address/address.html', 
     controller: AddressController, 
     controllerAs: 'dir' 
    }; 

I to magicznie pracował. Każdy pomysł DLACZEGO?

+0

Co masz w swoim szablonie 'modules/address/address.html'? Jeśli próbujesz odwołać się do 'vm' w ogóle w szablonie, to spowoduje to problem pusty, ponieważ' vm' nie istnieje w zakresie twojej dyrektywy. Również jeśli próbujesz po prostu powiązać 'adres' w szablonie dyrektywy, to również nie byłoby, ponieważ wiążisz kontroler jako' dir', więc musiałby to być 'dir.address' –

+0

In szablon odwołujemy się do elementów z 'dir':' '. Zmieniłem główny post, aby to wyjaśnić. Dzięki. – LeoLozes

+0

Proszę podać dwa plunery, w obu przypadkach. Istnieje proste wytłumaczenie tego, ale jest to zwykły tekst, który nie daje jasnego wyobrażenia o tym, co dokładnie zrobiłeś. – estus

Odpowiedz

18

Aktualizacja:

Dzięki reference to this blog post muszę aktualizować moją odpowiedź. Od angularjs 1.4 to naprawdę wydaje się, że można użyć

scope: {}, 
bindToController: { 
    variable: '=' 
} 

który zrobi (dokładne) samo jak starej składni:

scope: { 
    variable: '=' 
}, 
bindToController: true 

Użyteczne linie z kodem źródłowym angularjs Wyjaśniając to zachowanie:

if (isObject(directive.scope)) { 
    if (directive.bindToController === true) { 
    bindings.bindToController = parseIsolateBindings(directive.scope, 
                directiveName, true); 
    bindings.isolateScope = {}; 
    } else { 
    bindings.isolateScope = parseIsolateBindings(directive.scope, 
               directiveName, false); 
    } 
} 
if (isObject(directive.bindToController)) { 
    bindings.bindToController = 
     parseIsolateBindings(directive.bindToController, directiveName, true); 
} 

Źródło: AngularJS 1.4.0

Oryginalna odpowiedź:

Mam nadzieję, że mogę wyjaśnić, dlaczego to zachowanie, którego doświadczyłeś, jest poprawne i gdzie nie zrozumiałeś koncepcji zakresu wiążącego się z tym.

Pozwól mi wyjaśnić, co zrobiłeś w pierwszym fragmencie kodu:

.directive('mdAddress', function mdAddress() { 
    var directive = { 
     restrict: 'EA', 
     scope: {}, 
     bindToController: { 
     address: '=' 
     }, 
     templateUrl: 'modules/address/address.html', 
     controller: AddressController, 
     controllerAs: 'dir' 
    }; 

Z scope: {}, utworzony wyizolowaną zakresu (bez jakiegokolwiek spadku) do dyrektywy mdAddress. Oznacza to: Żadne dane nie są przekazywane pomiędzy kontrolerem nadrzędnym a twoją dyrektywą.

Mając to na uwadze, w odniesieniu do drugiego fragmentu kodu:

<md-address address="vm.address"></md-address> 

vm.address od kontrolera rodzic/widok zostanie przypisany jako wyrazu do atrybutu adresu dyrektywy, ale jak zdefiniowano wyizolowaną zakres przed , dane nie są przekazywane do AddressController i dlatego nie są dostępne w wartości bindToController.

Wyobraźmy sobie definicję obiektu scope jako "które dane zostaną przekazane" i bindToController jako "które dane będą dostępne w obiekcie kontrolera mojego widoku".

Więc teraz rzućmy okiem na ostatni (i kod roboczych fragment):

.directive('mdAddress', function mdAddress() { 
    var directive = { 
     restrict: 'EA', 
     scope: { 
     address: '=' 
     }, 
     bindToController: true, 
     templateUrl: 'modules/address/address.html', 
     controller: AddressController, 
     controllerAs: 'dir' 
    }; 

Istnieje utworzony wyizolowaną zakresu też, ale tym razem dodano atrybut address być przekazany jako ekspresja. Teraz address, który przekazałeś z widoku w drugim fragmencie, będzie dostępny w zasięgu kontrolera. Ustawienie bindToController: true spowoduje powiązanie wszystkich właściwości bieżącego zakresu z kontrolerem (lub, co bardziej prawdopodobne, z obiektem kontrolera). A teraz działa tak, jak można by oczekiwać, ponieważ dane zostaną przekazane do zakresu, a dane zostaną przekazane do zakresu szablonu kontrolera.

Czy ten krótki przegląd pomógł lepiej zrozumieć pojęcie obiektów definicji scope i bindToController?

+0

Dziękuję bardzo za odpowiedź! Ma to sens i całkowicie rozumiem drugą część twojego wyjaśnienia, ale pierwsza część wydaje się całkiem dosłownie przeciwieństwem artykułu, który łączyłem (o nowej funkcji bindToController). Zwłaszcza gdy jest napisane "Oznacza to, że możemy przesunąć nasz zakres: {name: '='} przykładowe powiązanie z nim, aby było bardziej jasne, że powiązania izolatów są w rzeczywistości dziedziczone i powiązane z kontrolerem", i zastępują 'scope: { name: '='}, bindToController: true' z 'scope: {}, bindToController: {nazwa: '='}'. – LeoLozes

+0

Rzeczywiście, dziękuję za odpowiedź. Masz rację, muszę przywrócić części mojej odpowiedzi. Ważną linią jest ta z kodu źródłowego AngularJS wspomnianego w artykule - więc zachowanie powinno być takie samo w obu przypadkach. Więc może masz jakiś dziwny błąd/literówkę w swoim kodzie? Czy możesz odtworzyć wszystko z twojego pytania? Bardzo ciekawy temat! – ConcurrentHashMap

+0

Dzięki, pomyślałem, że mogłem źle zrozumieć artykuł :). W każdym razie, przeglądając kod AngularJS, może to być tak, że 'scope: {}' zwraca 'isObject' jako true, ponieważ jest to pusty obiekt, a nie' null'? Wtedy wszedłby w pierwszą część 'if'sentence ... Sprawdziłem kod źródłowy AngularJS dla' isObject' ale nie jestem pewien ... – LeoLozes

Powiązane problemy