Reputation: 673
as the title says: Why does jQuery not remove all the data attributes?
<div data-subject-name="Spanisch" data-subject-id="9" data-subject-alias="Spa" data-category-id="1"></div>
$.fn.removeAttrs = function(regex) {
var regex = new RegExp(regex, "g");
return this.each(function() {
var _this = $(this);
console.log(this.attributes);
$.each(this.attributes, function(i, attrib){
console.log(attrib);
if (attrib && attrib.specified && regex.test(attrib.name)) {
console.log(attrib.name);
_this.removeAttr(attrib.name);
}
});
});
};
$('div').removeAttrs('^(data-)');
here is the http://jsfiddle.net/g2pXt/8/
i am using the snipped from Remove multiple html5 data-attributes with jquery @Mathias Bynens but it is not working. so whats the problem of this solution?
Upvotes: 3
Views: 1464
Reputation: 92903
You actually have two problems with your code, each of which is partially masking the other.
"test
called multiple times on the same global regular expression instance will advance past the previous match." As a result, every other time you performed .test
using the same regex, it wasn't searching from the beginning of the string. I replaced regex.test(str)
with str.search(regex)>=0
to solve this problem.
In addition, your script seemed to have indexing problems because you were removing attributes in the middle of the loop. I believe this is because "Arrays and array-like objects with a length property...are iterated by numeric index, from 0 to length-1." Removing the attributes all at once after the loop solved the problem (.removeAttr()
will accept a space-separated list of attributes to remove.)
$.fn.removeAttrs = function(regex) {
var regex = new RegExp(regex, "g");
return this.each(function() {
var _this = $(this);
var removethese = '';
$.each(this.attributes, function(i, attrib){
if (attrib && attrib.specified && attrib.name.search(regex)>=0) {
removethese += ' '+attrib.name;
}
});
_this.removeAttr(removethese);
});
};
http://jsfiddle.net/mblase75/YHyjC/
Note that using .removeAttr()
in this way is effectively repeating the loop a second time, so for maximum efficiency, you should retool your code and use a for
loop that counts backwards through this.attributes
and removes them at the same time. However, for a single short set of attributes, the performance gain will be minimal.
$.fn.removeAttrs = function(regex) {
var regex = new RegExp(regex, "g");
return this.each(function() {
var _this = $(this);
for (var i=this.attributes.length-1; i>=0; i--){
var attrib = this.attributes[i];
if (attrib && attrib.specified && attrib.name.search(regex)>=0) {
_this.removeAttr(attrib.name);
}
}; // end for
});
};
http://jsfiddle.net/mblase75/Zm4qR/
Upvotes: 6
Reputation: 36438
Your inner loop is iterating over a list of items that's changing underneath it.
The safest route is to use a straight-JS loop, from the end of the attributes list backward, so elements aren't skipped when a previous element has been deleted:
for ( var i = this.attributes.length - 1; i >= 0; --i ) {
var attrib = this.attributes[i];
if (attrib && attrib.specified && regex.test(attrib.name))
{
console.log(attrib.name);
_this.removeAttr(attrib.name);
}
}
Updated jsFiddle, including simplified regex: http://jsfiddle.net/g2pXt/36/
Upvotes: 2