如何编写angular指令,通过选择器来切换类
How to write angular directive that toggles classes by selector
我正试图编写一个指令,根据选择器条件切换类:
<label class-when="{'is-checked': ':has(input:checked)', 'is-disabled': ':has(input:disabled)'}">
<input type="checkbox">
Example checkbox
</label>
我需要以某种方式观察DOM对元素和它的后代的变化,但我得到一个ng:areq
错误。我该怎么做呢?
define(function (require) {
var _ = require('lodash');
return {
restrict: 'A',
scope: {
object: '@classWhen'
},
link: function (scope, element) {
scope.$watchCollection(function() {
return element.find('*').add(element);
}, function () {
_.forOwn(scope.object, function (test, classes) {
test = typeof test === 'boolean' ? test : element.is(test);
element.toggleClass(classes, test);
});
});
}
};
});
好的,在阅读了你的赏金评论后,我明白你希望这是独立于控制器的。我花了一些时间彻底修改我的解决方案,我想我终于找到了一种方法来实现你想要的。
可以归结为两件事:
1)检测复选框:checked
状态的变化,和
2)检测复选框:disabled
状态变化
检测1)
很容易,因为您可以使用一个简单的jQuery更改处理程序,但是检测2)
需要更多的研究。它要求在子ng-disabled
属性上使用scope.$watch
。
下面是如何工作的演示:
var app = angular.module("myApp", [])
.directive("classWhen", function() {
function setClasses(classWhen, $element, $input) {
Object.keys(classWhen).forEach(function(key) {
var test = classWhen[key];
// .toggleClass("className", true) === .addClass("className")
// .toggleClass("className", false) === .removeClass("className")
$element.toggleClass(key, $element.is(test));
});
}
return {
restrict: 'A',
link: function link (scope, element, attrs) {
var classWhen = JSON.parse(attrs.classWhen);
var $element = $(element);
$element.find("*").each(function (index, elem) {
var $elem = $(this);
// namespace the change event so we can easily .off() it
$elem.off("change.classWhen");
$elem.on("change.classWhen", function () {
setClasses(classWhen, $element, $elem);
});
// watch child ng-disabled attribute
scope.$watch($elem.attr("ng-disabled"), function (val) {
setClasses(classWhen, $element, $elem);
});
});
}
};
});
.is-checked {
background-color: yellow;
}
.is-disabled {
background-color: lightblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="myApp">
<label>
<input type="checkbox" ng-model="disableAll" />Disable All</label>
<br>
<br>
<label class-when='{"is-checked": ":has(input:checked)", "is-disabled": ":has(input:disabled)"}'>
<input type="checkbox" ng-disabled="disableAll">Example checkbox 1
</label>
<br>
<label class-when='{"is-checked": ":has(input:checked)", "is-disabled": ":has(input:disabled)"}'>
<input type="checkbox" ng-disabled="disableAll">Example checkbox 2
</label>
<br>
<label class-when='{"is-checked": ":has(input:checked, .test)", "is-disabled": ":has(input:disabled)"}'>
<input type="text" ng-disabled="disableAll" ng-class="testingClass" ng-model="testingClass"/>
<br>
<input type="checkbox" ng-disabled="disableAll">
Example checkbox 3
</label>
<br>
<label class-when='{"is-checked": ":has(input:checked)", "is-disabled": ":has(input:disabled)"}'>
<input type="checkbox" ng-disabled="disableAll">Example checkbox 4
</label>
</div>
这是我试图用通用的方式解决你的问题:https://plnkr.co/edit/kVyJQClmQhF3FeBTmKaX?p=preview
指令代码:
app.directive('classWhen', () => (scope, element, attrs) => {
scope.$watchCollection(getClasses, setClasses)
function getClasses() {
// We have to evaluate expression in attrs.classWhen so that we get object
const rawClasses = scope.$eval(attrs.classWhen)
const classes = {}
// then we normalize it so that strings are treated as jquery selectors
Object.keys(rawClasses).forEach((className) => {
const expr = rawClasses[className]
classes[className] = typeof expr === 'string'
? element.is(expr)
: !!expr // we normalize falsy values to booleans
})
// then we return it to $watchCollection
return classes
}
/**
* will be called whenever any of the classes changes
*/
function setClasses(classes) {
Object.keys(classes).forEach((className) => {
element.toggleClass(className, classes[className])
})
}
})
我已经创建了一个通用的小提琴,也与RequireJS作为你使用。
请看这里
http://fiddle.jshell.net/balasuar/dugmu/15/注意:无论你在选择器中添加了什么属性,如:checked
和:disabled
,将相关的角属性添加到子元素中,如ng-model
和ng-disabled
。它会像一个魅力!!
var app = window.app = angular.module("myApp", []);
define('classWhenDirective', function () {
//var _ = require('lodash');
var app = window.app;debugger;
app.directive("classWhen", function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$watch(getChanges, setClasses)
function getChanges() {
var attrs = [];
function getAttrs(elm) {
$.each(elm.attributes, function(i, attrib){
var name = attrib.name;
var value = attrib.value;
if(value && name.indexOf('ng-') > -1) {
value = scope.$eval(value);
}
if(value) {
attrs.push(name + ':' + value);
}
});
}
getAttrs(element.get(0));
element.children().each(function(){
getAttrs(this);
});
return attrs.join(',');
}
function setClasses() {
var rawClasses = scope.$eval(attrs.classWhen);
Object.keys(rawClasses).forEach(function(className){
var expr = rawClasses[className]
var setClass = typeof expr === 'string'
? element.is(expr)
: !!expr;
element.toggleClass(className, setClass);
});
}
}
};
});
});
define('todo', ['classWhenDirective'], function() {
var app = window.app;
app.controller('myController', function($scope) {
});
});
// angular bootstrap
require(['todo'], function() {
angular.bootstrap(document, ['myApp']);
});
.is-checked {
color: green;
}
.is-disabled {
color: gray;
}
<script src="http://requirejs.org/docs/release/2.0.6/minified/require.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<h2>ClassWhen Directive</h2>
<div ng-controller="myController">
<label>
<input type="checkbox" ng-model="disableAll" />Disable All</label>
<br>
<br>
<label class-when='{"is-checked": ":has(input:checked)", "is-disabled": ":has(input:disabled)"}'>
<input type="checkbox" ng-model="checkBox1" ng-disabled="disableAll">ClassWhen checkbox 1
</label>
<br>
<label class-when='{"is-checked": ":has(input:checked)", "is-disabled": ":has(input:disabled)"}'>
<input type="checkbox" ng-model="checkBox2" ng-disabled="disableAll">ClassWhen checkbox 2
</label>
</div>
相关文章:
- Windows8应用程序(html&Javascript):从图片库(除了文件选择器)显示图像的另一种方式
- 在动态创建的元素上获取对特定选择器的引用
- AngularJS-在JSON选择器中使用变量名
- 每当您在选择器内移动鼠标时,悬停功能就会重复
- 使用CSS或js,使用动态选择器选择任意li的下一个元素
- jQuery最近父级的数据属性选择器
- 为什么不'在JQuery中找到第二个css选择器的工作
- 为什么 .focus() 不起作用,而 .css(“color”,“red”) 在同一个选择器上起作用
- 编写一个类似jQuery的JS元素选择器
- Jquery自定义编写的选择器
- Qtip2:作为函数编写(并将不同的选择器作为参数传递)
- 如何编写一个jQuery选择器,在单个表达式中使用多个:eq's
- 如何编写一个选择器来查找第一个“输入”.在类为“x”的元素之后
- 如何在body选择器中编写自动补全
- 如何编写angular指令,通过选择器来切换类
- 带有代码编写器问题的Jquery日期选择器
- 在JQuery中为select-option-selected编写ID选择器的正确语法是什么?
- 在任何时间日期选择器中以编程方式设置时区偏移量
- 如何告诉jQuery,我编写的所有选择器都应该局限于正在处理的对象
- 编写一个jquery选择器来选择具有特定模式的类