Я пытаюсь получить атрибут оцененный из моей настраиваемой директивы, но я не могу найти правильный способ сделать это.
Я создал этот jsFiddle для разработки.
<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);
}
});
Что мне не хватает?
Примечание. Я обновляю этот ответ, когда нахожу лучшие решения. Я также сохраняю старые ответы для дальнейшего использования, пока они остаются связанными. Последний и лучший ответ на первом месте.
При создании директив angularjs позволяет создать изолированную область с некоторыми привязками к родительской области. Эти привязки указываются атрибутом , который вы прикрепляете к элементу в DOM и как вы определяете свойство scope в объекте определения директивы.
Существует 3 типа параметров привязки, которые вы можете определить в области видимости, и записывать их как атрибуты, связанные с префиксами.
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>
В этом случае, в рамках директивы (будь то функция связывания или контроллер), мы можем получить доступ к следующим свойствам следующим образом:
/* 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 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 .
Поскольку этот ответ принят, но есть некоторые проблемы, я собираюсь обновить его до лучшего. По-видимому, $parse
- это служба, которая не относится к свойствам текущей области, что означает, что она принимает только выражения angular и не может достигать области видимости.
{{
, }}
выражения скомпилированы в момент запуска angularjs, что означает, что когда мы пытаемся получить к ним доступ в нашем методе postlink
, они уже скомпилированы. ({{1+1}}
уже 2
в директиве).
Вот как вы хотели бы использовать:
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>
Одна вещь, которую вы должны заметить здесь, состоит в том, что, если вы хотите установить строку значений, ее следует обернуть в кавычки. (См. Третий вход)
Вот скрипка для игры: http://jsfiddle.net/neuTA/6/
Я не удаляю это для людей, которые могут быть введены в заблуждение, как я, обратите внимание, что использование $eval
отлично подходит для этого, но $parse
имеет другое поведение, вам, вероятно, это не понадобится для использования в большинстве случаев.
Способ сделать это, еще раз, используя scope.$eval
. Он не только компилирует выражение angular, но также имеет доступ к текущим свойствам области.
var myApp = angular.module('myApp',[]);
myApp.directive('myDirective', function () {
return function (scope, element, attr) {
element.val("value = "+ scope.$eval(attr.value));
}
});
function MyCtrl($scope) {
}
То, что вам не хватает, было $eval
.
http://docs.angularjs.org/api/ng.$rootScope.Scope#$eval
Выполняет выражение в текущей области, возвращающей результат. Любые исключения в выражении распространяются (неотображаются). Это полезно при оценке выражений angular.
Для значения атрибута, который должен быть интерполирован в директиве, которая не использует изолированную область видимости, например,
<input my-directive value="{{1+1}}">
использовать метод атрибутов $observe
:
myApp.directive('myDirective', function () {
return function (scope, element, attr) {
attr.$observe('value', function(actual_value) {
element.val("value = "+ actual_value);
})
}
});
На странице directive
соблюдение интерполированных атрибутов: используйте
$observe
для наблюдения за изменениями значений атрибутов, которые содержат интерполяцию (например,src="{{bar}}"
). Мало того, что это очень эффективно, но это также единственный способ легко получить фактическое значение, потому что во время фазы связывания интерполяция еще не была оценена, и поэтому значение в это время устанавливается наundefined
.
Если значение атрибута является только константой, например,
<input my-directive value="123">
вы можете использовать $eval, если значение является числом или логическим, и вы хотите ввести правильный тип:
return function (scope, element, attr) {
var number = scope.$eval(attr.value);
console.log(number, number + 1);
});
Если значение атрибута является строковой константой или вы хотите, чтобы значение было строковым типом в вашей директиве, вы можете получить к нему доступ напрямую:
return function (scope, element, attr) {
var str = attr.value;
console.log(str, str + " more");
});
В вашем случае, однако, поскольку вы хотите поддерживать интерполированные значения и константы, используйте $observe
.
Другие ответы здесь очень правильны и ценны. Но иногда вам просто нужно простое: получить простое старое анализируемое значение при создании экземпляра директивы, без необходимости обновления и без вмешательства в область выделения. Например, может быть полезно предоставить декларативную полезную нагрузку в вашу директиву в виде массива или хэш-объекта в форме:
my-directive-name="['string1', 'string2']"
В этом случае вы можете отрезать до погони и просто использовать хороший базовый angular.$eval(attr.attrName)
.
element.val("value = "+angular.$eval(attr.value));
Работа Fiddle.
Для того же решения я искал Angularjs directive with ng-Model
.
Вот код, который разрешает проблему.
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">
Мой результат:
92108-2223
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) {
}
Использовать $timeout, потому что директивный вызов после загрузки dom, поэтому ваши изменения не применяются
Много хороших ответов здесь, но иногда вам просто нужно простое, простое, старое решение jQuery-ish.
Мое решение не обрабатывает изменения в DOM. Если атрибут может измениться, не используйте мой метод!
В моем случае у меня был элемент, и мне нужно было получить значение атрибута (rel).
Шаблон:
<div ng-repeat="elm in array">
<button class="poi-lines-show" rel="li-{{$index}}">button-text</button>
</div>
В моей директиве:
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
}