Ответ 1
Почему избыточный избыток изоляции? его довольно полезно для такого рода вещей:
scope: {
"twoway": "=" // two way binding
},
Это довольно идиоматическое решение angular для этой проблемы, поэтому я придерживаюсь этого.
Если у меня есть директива AngularJS без шаблона, и я хочу, чтобы она установила свойство в текущей области, что это лучший способ сделать это?
Например, директива, которая подсчитывает нажатия кнопок:
<button twoway="counter">Click Me</button>
<p>Click Count: {{ counter }}</p>
С директивой, которая назначает счетчик кликов выражению в двухстороннем атрибуте:
.directive('twoway', [
'$parse',
function($parse) {
return {
scope: false,
link: function(scope, elem, attrs) {
elem.on('click', function() {
var current = scope.$eval(attrs.twoway) || 0;
$parse(attrs.twoway).assign(scope, ++current);
scope.$apply();
});
}
};
}
])
Есть ли лучший способ сделать это? Из того, что я прочитал, изолированный охват будет излишним, но мне нужен охват ребенка? И есть ли более чистый способ написать обратно переменную области видимости, определенную в атрибуте директивы, отличную от использования $parse
. Я просто чувствую, что делаю это слишком сложно.
Полный Plunker здесь.
Почему избыточный избыток изоляции? его довольно полезно для такого рода вещей:
scope: {
"twoway": "=" // two way binding
},
Это довольно идиоматическое решение angular для этой проблемы, поэтому я придерживаюсь этого.
Я удивлен, что никто не упомянул ng-model
, директиву по умолчанию для привязки двух данных. Возможно, это не так хорошо известно, но функция связывания имеет четвертый параметр:
angular.module('directive-binding', [])
.directive('twoway',
function() {
return {
require: '?ngModel',
link: function(scope, elem, attrs, ngModel) {
elem.on('click', function() {
var counter = ngModel.$viewValue ? ngModel.$viewValue : 0
ngModel.$setViewValue(++counter);
scope.$apply();
});
}
};
}
);
В вашем представлении
<button twoway ng-model="counter">Click Me</button>
<p>Click Count: {{ counter }}</p>
Четвертый параметр - это API для ngModelController, который имеет много применений для обработки (например, разбора и форматирования) и обмена данными между директивой и область действия.
Здесь обновлен Plunker.
Вы можете немного упростить его, не используя $parse
angular.module('directive-binding', []).directive('twoway', [function () {
return {
scope: false,
link: function (scope, elem, attrs) {
elem.on('click', function () {
scope[attrs.twoway] = scope[attrs.twoway] == null ? 1 : scope[attrs.twoway] + 1;
scope.$apply();
});
}
};
}]);
Отличным способом применения двусторонней привязки является использование директивных компонентов. Вот мое решение. Это позволяет использовать привязку ng-repeat и расширяемые данные.
HTML
<body ng-controller='MainCtrl'>
Data: {{data}}
<hr>
<mydirective name='data[0]'></mydirective>
<hr>
<mydirective name='data[1]'></mydirective>
</body>
контроллер
app.controller('MainCtrl', function($scope) {
$scope.data = [];
$scope.data[0] = 'Marco';
$scope.data[1] = 'Billy';
});
Директива
app.directive("mydirective", function(){
return {
restrict: "EA",
scope: {name: '='},
template: "<div>Your name is : {{name}}</div>"+
"Change your name : <input type='text' ng-model='name' />"
};
});
В случае счетчика это можно сделать с использованием того же метода.
Пользователь attrs.$set
:
attrs.$set('twoway', attrs.twoway++);
Посмотрите раздел "Атрибуты" http://docs.angularjs.org/guide/directive
Измените шаблон на:
<button twoway bind="counter">Click Me</button>
<p>Click Count: {{ counter.val }}</p>
и директива:
.directive('twoway',
function() {
return {
scope: {
localValue: '=?bind'
},
link: function(scope, elem, attrs) {
scope.localValue = {
val: 0
};
elem.on('click', function() {
scope.localValue.val = scope.localValue.val + 1;
scope.$apply();
});
}
};
}
);