Как я могу создать директиву, которая добавляет ng-class и NG-disabled на целевом элементе на основе условия?
у меня есть следующий код:
app.directive "ngDisableOnVar", ($compile) ->
restrict: "A"
terminal: true
priority: 1000
replace:false
scope: {}
compile: compile = (element, attrs) ->
cattr = attrs["ngDisableOnVar"]
element.attr("ng-class", "{'disabled': !#{cattr}}")
element.attr("ng-disabled", "!#{cattr}")
element.removeAttr("ng-disable-on-var")
pre: preLink = (scope, iElement, iAttrs, controller) ->
post: postLink = (scope, iElement, iAttrs, controller) ->
$compile(iElement)(scope)
Я попытался основать код на данном ответе здесь. В принципе, я хотел бы иметь следующее:
<input ngDisableOnVar="someScopeVariable>
и заменить его следующим:
<input ng-class="{'disabled': !someScopeVariable}" ng-disabled="!someScopeVariable">
что-то не так, потому что, хотя я применил их к моему элементу, они всегда отключены, даже если переменная scope оценивается как true. Что я делаю не так?
изменить: Я создал plunker, где первые 2 кнопки создаются с ng-class и NG-disabled, а другие 2 кнопки должны иметь те же самые вещи, применяемые к ним с помощью директивы.
вот версия plunker с общей областью:http://plnkr.co/edit/TebCQL20ubh5AgJ6nMIl?p=preview
и вот один без общей области:http://plnkr.co/edit/CPm55MrHA8z6Bx4GbxoN?p=preview
проблема в том, что тот, у кого нет общей области, делает не обновлять. Как я могу их обновить, и условия зависят от переменных, переданных в качестве аргументов?
Изменить #2: Я начинаю верить, что совместное использование области-это правильный способ действия этих 2 кнопок, за исключением создания новой директивы, которая инкапсулирует обе кнопки внутри нее. Хотя не на 100% уверен.
4 ответов
Я бы пошел с вашим EDIT #2, потому что они связаны. Если мы создаем их как отдельные элементы, нам нужно каким-то образом передать связанный элемент каждому => когда мы нажимаем на кнопку 1, мы обновляем себя, а также связанный элемент.
здесь я изменил ваш первый подход, чтобы заставить его работать:http://plnkr.co/edit/KgYIlATiw9xzTEZt9Jv1?p=preview
в этом примере я должен передать связанный элемент каждой директиве, чтобы, когда мы нажмите мы можем обновить себя и связанный элемент:
related-element="btnForward"
я внес некоторые изменения в директиву:
scope: {
reactOn: "=", //use property binding instead of function binding
relatedElement:"@"
},
link: function(scope, element, attrs) {
scope.toggle = function(){
scope.reactOn = !scope.reactOn;//toggle current element
var relatedScope = $("#"+scope.relatedElement).scope();//get related element's scope and toggle it
relatedScope.reactOn = !relatedScope.reactOn;
}
//var cattr = attrs.ngDisableReactOn;
element.attr("ng-class", "{'disabled': !reactOn}"); //Use reactOn instead as this is the property of current scope
element.attr("ng-disabled", "!reactOn");
element.attr("ng-click", "toggle()");
element.removeAttr("ng-disable-react-on");
$compile(element)(scope);
}
нам не нужно усложнять ситуацию. Просто создайте нормальную директиву, чтобы обернуть 2 кнопки.
myApp.directive("ngDisableReactOn", function($compile) {
return {
restrict: "A",
templateUrl:"ngDisableReactOn.html",
scope: {
can_go_back: "@"
},
link: function(scope, element, attrs) {
scope.goBack = function(){
scope.can_go_back = false;
}
scope.goFwd = function(){
scope.can_go_back = true;
}
}
}
});
шаблон:
<input type="button" value="go back" ng-click="goBack()" ng-class="{'disabled': !can_go_back}" ng-disabled="!can_go_back">
<input type="button" value="go fwd" ng-click="goFwd()" ng-class="{'disabled': can_go_back}" ng-disabled="can_go_back">
другое решение-создать родительские директивы как контейнер. Это решение мне нравится больше всего. При таком подходе вы можете свободно изменять внутреннее содержание директивы как добавление больше кнопок, больше текста,....(НЕ НУЖНО HARDCODE ШАБЛОН) родительская директива работает как менеджер, чтобы гарантировать, что есть только 1 активный ребенок одновременно:
myApp.directive("ngDisableReactOnContainer", function() { //Container directive to manage all child directives
return {
restrict: 'EA',
replace: true,
transclude: true,//Use transclusion to move inner content to the template
template: '<div ng-transclude></div>',
controller: function() {
var children = [];
this.selectChild = function(activeChild) { //ensure that only 1 child is active at a time
activeChild.active = true;
angular.forEach(children, function(child) {
if (child != activeChild) {
child.active = false;
}
});
}
this.addChild = function(child) {
children.push(child);
}
}
};
});
myApp.directive("ngDisableReactOn", function($compile) {
return {
restrict: "A",
scope:{
active:"@"
},
require: '^?ngDisableReactOnContainer',
link: function(scope, element, attrs, controller) {
scope.active = scope.active === 'true';
controller.addChild(scope);//register itself with the container
scope.select = function(){//When this element is clicked, inform the container to toggle all children accordingly.
controller.selectChild(scope);
}
//Add ng-class and ng-disabled based on your requirement.
element.attr("ng-class", "{'disabled': active}"); //Use active instead as this is the property of current scope
element.attr("ng-disabled", "active");
element.attr("ng-click", "select()");
element.removeAttr("ng-disable-react-on");
$compile(element)(scope);
}
}
});
использование этих директив было бы просто:
<div ng-disable-react-on-container>
<input ng-disable-react-on type="button" value="button 1" active="true" >
<input ng-disable-react-on type="button" value="button 2" >
<input ng-disable-react-on type="button" value="button 3" >
</div>
вот очень уродливый способ продемонстрировать, как скомпилировать шаблон во время функции link. Это уродливо, потому что я не обращался к какой-либо привязке к переменной области. Возможно, вы захотите изолировать область или настроить двустороннюю привязку, но это должно дать вам суть доступа к области для целей компиляции.
app.directive('foo', function($compile) {
return function(scope, elem, attrs) {
var html;
if (scope.testVar)
html = '<input ng-class="{\'disabled\': !someScopeVariable}" ng-disabled="!someScopeVariable" />';
else
html = '<input />';
var htmlEl = angular.element(html),
compiledEl = $compile(htmlEl)(scope);
elem.replaceWith(compiledEl);
}
});
вы можете получить тот же эффект с другой схожий подход. Плюх здесь
вместо $compile
в функции link вы можете использовать template
в вашей директиве и ng-disabled
с переменной в области, которая привязана к переменной родительской области через изолированную область.
вы пытались удалить !
перед именем var?
<input ng-class="{'disabled': someScopeVariable}" ng-disabled="someScopeVariable">