2013-09-06 12 views
6

przy użyciu AngularJS. Mam dyrektywę, że chcę mieć dwukierunkowe powiązanie danych. Dyrektywa będzie miała atrybut o nazwie "aktywuj". Początkowo wartość "aktywuj" będzie wynosić "1".Zmień atrybut z dyrektywy

Funkcja łącza do dyrektywy sprawdzi, czy "aktywacja" jest równa "1". Jeśli tak, zmieni "uaktywnij" na 0, ale zrobi też inne rzeczy.

Później, jeśli chcę, aby dyrektywa ponownie wykonała pewne czynności, w kontrolerze ponownie zmienię "aktywuj" na "1". Ponieważ dyrektywa ma zegarek, powtórzy cykl.

Niestety, za każdym razem, gdy to robię, pojawia się "Wyrażenie" 0 "użyte w dyrektywie" testDirective "jest nieprzenoszalne!" lub "Niepowtarzalne wyrażenie modelu: 1 (dyrektywa: testDirective)".

Oto HTML:

<body ng-app="app"> 
    <test-directive activate="1"></test-directive>  
</body> 

Oto JS:

var app = angular.module('app', []); 


app.directive('testDirective', function() { 
    return { 
     restrict: 'E', 
     scope: { 
      activate : '=' 
     }, 


     link: function(scope, elem, attrs, controller) { 
      var el = elem[0]; 

      var updateContent = function() { 
       el.innerText = 'Activate=' + scope.activate; 
      }; 

      updateContent(); 
      attrs.$observe('activate', function() { 
       console.log('Activate=' + scope.activate); 
       if(scope.activate == '1') { 
        scope.activate = '0' 
        updateContent(); 
       } 
      }); 
     } 
    } 
});  

Oto ona na jsFiddle: http://jsfiddle.net/justbn/mgSpY/3/

Dlaczego nie mogę zmienić wartość zapisaną w atrybucie tej dyrektywy ? Używam 2-way binding.

Dokumenty mówią: "Jeśli właściwość zasięgu nadrzędnego nie istnieje, zostanie zgłoszony wyjątek NON_ASSIGNABLE_MODEL_EXPRESSION."

UWAGA: Treść aktualizacji prawidłowo pokazuje wartość "aktywuj". Jednak wartość "aktywuj" w "" nie aktualizuje się.

Jednak to nie ma dla mnie żadnego sensu, ponieważ właściwość zakresu rodzica istnieje.

Wszelkie pomysły?

Odpowiedz

12

Chociaż zgadzam się z użyciem $watch zamiast attrs.$observe, to nie jest główny powód komunikatu o błędzie, który otrzymujesz.

Problemem jest to, że starają się przypisać wartość do niezbywalnej wypowiedzi - jak komunikat o błędzie mówi ci: Non-assignable model expression: 1 (directive: testDirective)

Objęty zakazem cesji wyraz w tym przypadku jest numerem „1”

<test-directive activate="1"> 

zarządzać przekazać wartość początkową (1) do dyrektywy, ale kiedy dyrektywa próbuje zaktualizować tę wartość atrybutu aktywować nie może być zmieniony - bo jest to liczba.

To, co musisz zrobić, to zmienić to na zmienną, abyś mógł zaktualizować wartość później.

Zobacz kod poniżej, w którym inicjalizuję zmienną w polu $ scope o nazwie activate.initialValue za pomocą kontrolera.

I użyłem także $watch zamiast attrs.$observe.

Dodałem $timeout tylko po to, aby symulować zdarzenie, aby zmienić wartość aktywacji po 2 sekundach.

HTML

<body ng-app="app" ng-controller="appCtrl"> 
    <test-directive activate="activate.initialValue"></test-directive>  
</body> 

JS

var app = angular.module('app', []); 

app.controller('appCtrl', function($scope){ 
    $scope.activate = { 
     initialValue : 1 
    } 
}); 

var app = angular.module('app', []); 

app.controller('appCtrl', function($scope){ 
    $scope.activate = { 
     initialValue : 2 
    } 
}); 

app.directive('testDirective', function($timeout) { 
    return { 
     restrict: 'E', 
     scope: { 
      activate : '=' 
     },  
     link: function(scope, elem, attrs) { 
      scope.$watch('activate', function(newValue, oldValue){ 
       console.log('activate has changed', newValue); 
      }); 

      $timeout(function(){ 
        scope.activate = 0;  
       }, 2000); 
     }, 
     template: "{{activate}}" 
    } 
}); 

Można również zobaczyć tu pracuje (http://jsfiddle.net/mgSpY/63/).

I oto jest angularjs oficjalna dokumentacja o tym (http://docs.angularjs.org/error/ngModel:nonassign)

+0

dluz: Podałem odpowiedź Michaelowi za działające rozwiązanie. Ale po prostu zmieniłem to dla ciebie. Wyjaśniłeś to, aby lepiej to zrozumieć. Dzięki wielkie! – Justin

+0

Justin: chętnie pomożemy! :) –

+0

To była część odpowiedzi dla mnie. Musiałem również uruchomić lunetę. $ Apply() po modyfikacji, lub $ watch nie wyzwoli. – LucasBeef

3

Aby monitorować obiekt zakresu, należy użyć scope.$watch zamiast attrs.$observe:

link: function(scope, elem, attrs, controller) { 
    var el = elem[0]; 

    var updateContent = function() { 
    el.innerText = 'Activate=' + scope.activate; 
    }; 

    scope.$watch('activate', function(value) {        
    console.log('Activate=', value); 
    if(value === 1) { 
     scope.activate = '0'      
    } 
    updateContent(); 
    }); 
} 

jsFiddle here.

Należy zauważyć, że usunięto wywołanie updateContent z funkcji łącza, ponieważ można bezpiecznie uzyskać dostęp do właściwości zakresu wewnątrz odwołania zwrotnego $watch, chyba że można zapewnić, że wartość związana z tą właściwością jest dostępna przed dyrektywą jest przetwarzany przez Angular.

$observe należy używać wyłącznie do obserwowania/obserwowania zmian wartości atrybutu DOM zawierającego interpolację (na przykład value="{{ value }}"). Sprawdź to SO question, aby lepiej to zrozumieć.

+0

Michael: Dziękuję bardzo za odpowiedź. To na pewno działa poprawnie teraz. Nie do końca rozumiem, jak działa "scope.activate = 0" teraz, ale nie wcześniej. Nadal zmieniam wartość tego samego atrybutu. – Justin

+0

Zaktualizuję odpowiedź, podając więcej informacji. Mam nadzieję, że to wszystko wyjaśni. –

Powiązane problemy