Jak uzyskać ocenione atrybuty wewnątrz dyrektywy niestandardowej

Próbuję uzyskać oceniony atrybut z mojej niestandardowej dyrektywy, ale nie mogę znaleźć odpowiedniego sposobu na zrobienie tego.

Stworzyłem ten jsFiddle do rozwinięcia.

<div ng-controller="MyCtrl">
    <input my-directive value="123">
    <input my-directive value="{{1+1}}">
</div>

myApp.directive('myDirective', function () {
    return function (scope, element, attr) {
        element.val("value = "+attr.value);
    }
});
Co mi umyka?
Author: Voles, 2012-09-11

6 answers

Uwaga: aktualizuję tę odpowiedź, ponieważ znajduję lepsze rozwiązania. Zachowuję również stare odpowiedzi do przyszłego odniesienia, o ile pozostaną ze sobą powiązane. Najnowsza i najlepsza odpowiedź jest na pierwszym miejscu.

Lepsza odpowiedź:

Dyrektywy w angularjs są bardzo potężne, ale potrzeba czasu, aby zrozumieć, które procesy za nimi stoją.

Podczas tworzenia dyrektyw, angularjs pozwala na utworzenie izolowanego zakresu z pewnymi powiązaniami z zakresem nadrzędnym. Te wiązania są określone atrybutem dołączasz element w DOM i jak definiujesz właściwość scope w obiekcie definicji dyrektywy .

Istnieją 3 typy opcji wiążących, które można zdefiniować w scope i zapisać je jako atrybut związany z prefiksami.

angular.module("myApp", []).directive("myDirective", function () {
    return {
        restrict: "A",
        scope: {
            text: "@myText",
            twoWayBind: "=myTwoWayBind",
            oneWayBind: "&myOneWayBind"
        }
    };
}).controller("myController", function ($scope) {
    $scope.foo = {name: "Umur"};
    $scope.bar = "qwe";
});

HTML

<div ng-controller="myController">
    <div my-directive my-text="hello {{ bar }}" my-two-way-bind="foo" my-one-way-bind="bar">
    </div>
</div>

W takim przypadku, w zakresie dyrektywy (czy to w funkcji linkującej czy w kontrolerze), możemy uzyskać dostęp do takich właściwości jak to:

/* Directive scope */

in: $scope.text
out: "hello qwe"
// this would automatically update the changes of value in digest
// this is always string as dom attributes values are always strings

in: $scope.twoWayBind
out: {name:"Umur"}
// this would automatically update the changes of value in digest
// changes in this will be reflected in parent scope

// in directive's scope
in: $scope.twoWayBind.name = "John"

//in parent scope
in: $scope.foo.name
out: "John"


in: $scope.oneWayBind() // notice the function call, this binding is read only
out: "qwe"
// any changes here will not reflect in parent, as this only a getter .

"nadal OK" odpowiedź:

Ponieważ ta odpowiedź została zaakceptowana, ale ma pewne problemy, zaktualizuję ją do lepszego. Najwyraźniej $parse jest usługą, która nie leży we właściwościach bieżącego zakresu, co oznacza, że zajmuje tylko wyrażenia kątowe i nie może osiągnąć zakresu. {{,}} wyrażenia są kompilowane podczas inicjowania angularjs, co oznacza, że gdy próbujemy uzyskać do nich dostęp w naszej metodzie dyrektyw postlink, są one już kompilowane. ({{1+1}} jest 2 w dyrektywa już).

Tak chciałbyś użyć:

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

myApp.directive('myDirective', function ($parse) {
    return function (scope, element, attr) {
        element.val("value=" + $parse(attr.myDirective)(scope));
    };
});

function MyCtrl($scope) {
    $scope.aaa = 3432;
}​

.

<div ng-controller="MyCtrl">
    <input my-directive="123">
    <input my-directive="1+1">
    <input my-directive="'1+1'">
    <input my-directive="aaa">
</div>​​​​​​​​

Należy zauważyć, że jeśli chcesz ustawić łańcuch wartości, powinieneś zawinąć go w cudzysłowy. (Patrz 3. wejście)

Oto skrzypce do zabawy: http://jsfiddle.net/neuTA/6/

Stara Odpowiedź:

nie usuwam tego dla ludzi, którzy mogą być wprowadzani w błąd, jak ja, zauważ, że używanie $eval jest całkowicie poprawne, ale $parse ma inne zachowanie, prawdopodobnie nie będzie to potrzebne do użycia w większości przypadków.

Sposobem na to jest, po raz kolejny, użycie scope.$eval. Nie tylko kompiluje wyrażenie kątowe, ale ma również dostęp do właściwości bieżącego zakresu.

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

myApp.directive('myDirective', function () {
    return function (scope, element, attr) {
        element.val("value = "+ scope.$eval(attr.value));
    }
});

function MyCtrl($scope) {

}​

Brakuje ci $eval.

Http://docs.angularjs.org/api/ng.$rootScope. Scope#$eval

Wykonuje wyrażenie na bieżącym obszarze zwracając wynik. Wszelkie wyjątki w wyrażenie jest propagowane (uncaught). Jest to przydatne przy ocenie wyrażeń kątowych.

 558
Author: Umur Kontacı,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-24 10:08:30

Dla wartości atrybutu, która musi być interpolowana w dyrektywie, która nie używa izolowanego zakresu, np.

<input my-directive value="{{1+1}}">

Użyj metody atrybutów $observe:

myApp.directive('myDirective', function () {
  return function (scope, element, attr) {
    attr.$observe('value', function(actual_value) {
      element.val("value = "+ actual_value);
    })
 }
});

Ze strony dyrektywy ,

Obserwacja interpolowanych atrybutów: Użyj $observe, aby obserwować zmiany wartości atrybutów zawierających interpolację(np. src="{{bar}}"). Nie tylko jest to bardzo wydajne, ale jest to również jedyny sposób na łatwe uzyskanie rzeczywistej wartości, ponieważ podczas łączenia Faza interpolacja nie została jeszcze oceniona, więc wartość jest w tym momencie ustawiona na undefined.

Jeśli wartość atrybutu jest tylko stałą, np.

<input my-directive value="123">

Możesz użyć $eval jeśli wartość jest liczbą lub wartością logiczną i chcesz mieć prawidłowy typ:

return function (scope, element, attr) {
   var number = scope.$eval(attr.value);
   console.log(number, number + 1);
});

Jeśli wartość atrybutu jest stałą łańcuchową lub chcesz, aby wartość była typu string w Twojej dyrektywie, możesz uzyskać do niej bezpośredni dostęp:

return function (scope, element, attr) {
   var str = attr.value;
   console.log(str, str + " more");
});

W Twoim przypadku, jednak, ponieważ chcesz obsługa wartości interpolowanych i stałych, użyj $observe.

 80
Author: Mark Rajcok,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-01 21:39:21

Inne odpowiedzi tutaj są bardzo poprawne i cenne. Ale czasami po prostu chcesz proste: aby uzyskać zwykłą starą parsowaną wartość w instancjacji dyrektywy, bez konieczności aktualizacji, i bez mieszania z izolować zakres. Na przykład, może być przydatne dostarczenie deklaratywnego ładunku do dyrektywy w postaci tablicy lub obiektu hash w postaci:

my-directive-name="['string1', 'string2']"
W takim razie możesz przejść do sedna i po prostu użyć ładnego podstawowego angular.$eval(attr.attrName).
element.val("value = "+angular.$eval(attr.value));

Praca Skrzypce .

 4
Author: XML,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-05 16:00:36

Dla tego samego rozwiązania, którego szukałem Angularjs directive with ng-Model.
Oto kod, który rozwiązuje problem.

    myApp.directive('zipcodeformatter', function () {
    return {
        restrict: 'A', // only activate on element attribute
        require: '?ngModel', // get a hold of NgModelController
        link: function (scope, element, attrs, ngModel) {

            scope.$watch(attrs.ngModel, function (v) {
                if (v) {
                    console.log('value changed, new value is: ' + v + ' ' + v.length);
                    if (v.length > 5) {
                        var newzip = v.replace("-", '');
                        var str = newzip.substring(0, 5) + '-' + newzip.substring(5, newzip.length);
                        element.val(str);

                    } else {
                        element.val(v);
                    }

                }

            });

        }
    };
});


HTML DOM

<input maxlength="10" zipcodeformatter onkeypress="return isNumberKey(event)" placeholder="Zipcode" type="text" ng-readonly="!checked" name="zipcode" id="postal_code" class="form-control input-sm" ng-model="patient.shippingZipcode" required ng-required="true">


mój wynik to:

92108-2223
 4
Author: Satish Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-27 13:14:21
var myApp = angular.module('myApp',[]);

myApp .directive('myDirective', function ($timeout) {
    return function (scope, element, attr) {
        $timeout(function(){
            element.val("value = "+attr.value);
        });

    }
});

function MyCtrl($scope) {

}

Użyj $ timeout, ponieważ dyrektywa wywołuje po załadowaniu dom, więc twoje zmiany nie mają zastosowania

 2
Author: user1693371,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-02 07:54:45

Wiele dobrych odpowiedzi tutaj, ale czasami po prostu chcesz zwykły, łatwy, Stary, jQuery-owski, rozwiązanie.

Moje rozwiązanie nie obsługuje zmian w DOM. Jeśli atrybut może się zmienić, nie używaj mojej metody!

W moim przypadku miałem element i musiałem pobrać wartość atrybutu (rel).

Szablon:

<div ng-repeat="elm in array">
    <button class="poi-lines-show" rel="li-{{$index}}">button-text</button>
</div>

In my directive:

var buttons = element[0].querySelectorAll('button');
for (var i=0; i<buttons.length; i++) {
    var target = angular.element(buttons[i]);
    console.log(target.attr('rel')); // Outputs 'li-0', 'li-1', 'li-2' etc 
}
 -4
Author: qualbeen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-31 08:54:08