I have an array like treeids = ['a','b','c','d'];
I want to remove the 'b' element. By Using index we can do, but i want this with out using index, because those values comes dynamically into this array.
Just remove with the name only.
It should support in IE7 browser.
How to do this.
Thanks
JavaScript 1.6 provides Array.filter, which would suit your needs spot on.
Of course, as you can see from the Browser support table at the bottom, if you must support IE older then IE 9, you're out of luck.
jQuery provides jQuery.grep which does the same thing, but introduces the overhead of a separate library.
Underscore.js has _.filter, but again, this would be using a separate library for only one purpose.
try the following:
treeids.splice(treeids.indexOf('b'), 1);
Now treeids will contain the remaining...Here 'b' was the element to be removed. The argument of indexOf can come from a variable. Additionally you should check for error: the index shouldn't be -1.
This removes all the 'b's:
Array.prototype.remove= function(item){
var L= this.length, indexed;
while(L){
indexed= this[--L];
if(indexed=== itm) this.splice(L, 1);
}
return this;
}
splice is available in IE7 (and 6). It removes the number of items passed in the second argument, starting at the index specified by the first.
Related
Here is some I just noticed and im asking if its normal. Im using a .length property inside a .substr(), but it seems like the value of .length change during the .substr(). Here is a example here : https://jsfiddle.net/L11yg3y0/1/
var immastring = "Metaphysics"
var test = immastring.substr(2,immastring.length-2);
alert(test);
Shouldn't it output "taphysi" instead of "taphysics"? Because right now, it means that in the method .substr, they first remove the first two character, actualize the .length value and then remove the last two character.
I was just wondering because I already used this kind of method in other language like c++ and c#, but it wasn't working that way.
.substr takes the start index and the length of the substring. "Metaphysics" has length 11, so immastring.length - 2 is 9. "taphysics".length is indeed 9.
If you want to specify the end index, use .substring instead.
JavaScript has two substring methods, you picked the wrong one.
str.substr(start[, length])
vs
str.substring(indexStart[, indexEnd])
References:
MDN substr
MDN substring
element.classList is of DOMTokenList type.
Is there a method to clear this list?
I'm not aware of a "method" in the sense of a "function" associated with classList. It has .add() and .remove() methods to add or remove individual classes, but you can clear the list in the sense of removing all classes from the element like this:
element.className = "";
With ES6 and the spread operator, this is a breeze.
element.classList.remove(...element.classList);
This will spread the list items as arguments to the remove method.
Since the classList.remove method can take many arguments, they all are removed and the classList is cleared.
Even though it is readable it is not very efficient. #Fredrik Macrobond's answer is faster.
View different solutions and their test results at jsperf.
var classList = element.classList;
while (classList.length > 0) {
classList.remove(classList.item(0));
}
Here's another way to do it:
element.setAttribute("class", "")
Nowadays, classList is preferred to (remove|set)Attribute or className.
Pekaaw's answer above is good, 1 similar alternative is to set the DomTokenList.value
elem.classList.value = ''
Another option is to simply remove the class attribute:
elem.removeAttribute('class')
I recommend not using className as classList could result in faster DOM updates.
The remove() method of DOMTokenList (which is what classList is) can take multiple arguments - each a string of a classname to remove (reference). First you need to convert the classList to a plan array of classnames. Some people use Array.prototype.slice() to do that, but I'm not a fan and I think a for loop is faster in most browsers - but either way I have nothing against for loops and the slice often feels like a hack to me. Once you have the array you simply use apply() to pass that array as a list of arguments.
I use a utility class I wrote to accomplish this. The first method is the one you are looking for, but I'm including slightly more for your reference.
ElementTools.clearClassList = function(elem) {
var classList = elem.classList;
var classListAsArray = new Array(classList.length);
for (var i = 0, len = classList.length; i < len; i++) {
classListAsArray[i] = classList[i];
}
ElementTools.removeClassList(elem, classListAsArray);
}
ElementTools.removeClassList = function(elem, classArray) {
var classList = elem.classList;
classList.remove.apply(classList, classArray);
};
ElementTools.addClassList = function(elem, newClassArray) {
var classList = elem.classList;
classList.add.apply(classList, newClassArray);
};
ElementTools.setClassList = function(elem, newClassArray) {
ElementTools.clearClassList(elem);
ElementTools.addClassList(elem, newClassArray);
};
Please note that I have not thoroughly tested this in all browsers as the project I am working on only needs to work in a very limited set of modern browsers. But it should work back to IE10, and if you include a shim (https://github.com/eligrey/classList.js) for classList, it should work back to IE7 (and also with SVGs since Eli Grey's shim adds support for SVG in unsupported browsers too).
An alternative approach I considered was to loop backwards through the classList and call remove() on classList for each entry. (Backwards because the length changes as you remove each.) While this should also work, I figured using the multiple arguments on remove() could be faster since modern browsers may optimize for it and avoid multiple updates to the DOM each time I call remove() in a for loop. Additionally both approaches require a for loop (either to build a list or to remove each) so I saw no benefits to this alternative approach. But again, I did not do any speed tests.
If somebody tests speeds of the various approaches or has a better solution, please post.
EDIT: I found a bug in the shim which stops it from correctly adding support to IE11/10 for multiple arguments to add() and remove(). I have filed a report on github.
For reference, here's an article on Creating a Custom Filter Selector with jQuery.
Introduction:
For those not familiar with jQuery's Custom Filter Selectors, here's a quick primer on what they are:
If you need a reusable filter, you can extend jQuery’s selector expressions by adding your own functions to the jQuery.expr[':'] object.
The function will be run on each element in the current collection and should return true or false (much like filter). Three bits of information are passed to this function:
The element in question
The index of this element among the entire collection
A match array returned from a regular expression match that contains important information for the more complex expressions.
Once you've extended jQuery.expr[':'], you can use it as a filter in your jQuery selector, much like you would use any of the built-in ones (:first, :last, :eq() etc.)
Here's an example where we'll filter for elements that have more than one class assigned to them:
jQuery.expr[':'].hasMultipleClasses = function(elem, index, match) {
return elem.className.split(' ').length > 1;
};
$('div:hasMultipleClasses');
Here's the fiddle: http://jsfiddle.net/acTeJ/
In the example above, we have not used the match array being passed in to our function. Let's try a more complex example. Here we'll create a filter to match elements that have a higher tabindex than the number specified:
jQuery.expr[':'].tabindexAbove = function(elem, index, match) {
return +elem.getAttribute('tabindex') > match[3];
};
$('input:tabindexAbove(4)');
Here's the fiddle: http://jsfiddle.net/YCsCm/
The reason this works is because the match array is the actual array returned from the regex that was used to parse the selector. So in our example, match would be the following array:
[":tabIndexAbove(4)", "tabIndexAbove", "", "4"]
As you can see, we can get to the value inside the parentheses by using match[3].
The Question:
In jQuery 1.8, the match array is no longer being passed in to the filter function. Since we have no access to the info being passed in, the tabindexAbove filter does not work anymore (the only difference between this fiddle and the one above, is that this uses a later version of jQuery).
So, here are several points I'd like clarified:
Is this expected behavior? Is it documented anywhere?
Does this have anything to do with the fact that Sizzle has been updated (even though it clearly states that "the old API for Sizzle was not changed in this rewrite". Maybe this is what they mean by "the removal of the now unnecessary Sizzle.filter")?
Now that we have no access to the match array, is there any other way to get to the info being passed in to the filter (in our case, 4)?
I never found any documentation in the jQuery Docs about the custom filter selectors, so I don't know where to start looking for information about this.
jQuery has added a utility for creating custom pseudos in Sizzle. It's a little more verbose, but it's much more readable than using match[3]. It also has the advantage of being more performant as you can avoid repeating tedious calculations every time an element is tested. The answer that has already been accepted is a good answer, but let me add a note to say that you can use $.expr.createPseudo instead of setting the sizzleFilter property yourself, which will save a little space.
jQuery.expr[':'].tabIndexAbove = $.expr.createPseudo(function( tabindex ) {
return function(elem) {
return +elem.getAttribute('tabindex') > tabindex;
}
});
$('input:tabIndexAbove(4)').css('background', 'teal');
jsfiddle: http://jsfiddle.net/timmywil/YCsCm/7/
This is all documented on Sizzle's github:
https://github.com/jquery/sizzle/wiki/Sizzle-Documentation
By looking at the jQuery 1.8 beta2 source and the "Extensibility" section of The New Sizzle, you have to set fn.sizzleFilter to true in order to get the pseudo argument and the context. If not, you'll just get all the elements in the arguments.
Here is the code that does the same thing as your example. Use the selector parameter passed in the function to get the pseudo argument.
Here is the working example on jsfiddle.
As mentioned in the blog post above, you can even pre-compile and cache the your selector.
var sizzle = jQuery.find;
var tabIndexAbove = function( selector, context, isXml ) {
return function( elem ) {
return elem.getAttribute("tabindex") > selector;
};
};
/*
fn.sizzleFilter is set to true to indicate that tabIndexAbove
is a function that will return a function for use by the compiler
and should be passed the pseudo argument, the context, and
whether or not the current context is xml. If this property is
not set, adding pseudos works similar to past versions of Sizzle
*/
tabIndexAbove.sizzleFilter = true;
sizzle.selectors.pseudos.tabIndexAbove = tabIndexAbove;
$('input:tabIndexAbove(4)').css('background', 'teal');
Just a note, if you're looking at the source, jQuery slightly changed the structure that the public-facing interface points to.
In jQuery 1.7.2:
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.filters;
In jQuery 1.8b2:
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[":"] = jQuery.expr.pseudos;
I've been trying to work out the best way to define a certain element, which is present an arbitrary number of times throughout a page, without requiring:
the 'name' attribute; or
definition of a new element (XHTML).
I am essentially after the 'name' attribute; however, it appears redundant, obsolete and depreciated in parts.
I am hoping to isolate and manipulate said elements using JavaScript, and preferably avoiding jQuery. Is there a reasonable solution? So far I've thought of:
iterating through all elements with a certain tag and checking for a specific className; or
using incremental IDs on the elements (e.g. el1, el2, el3) and iterating through the sequence until getElementById returns null (feels botchy and only sort of what I'm after).
Thanks :)
querySelectorAll returns a list of the elements within the document (using depth-first pre-order traversal of the document's nodes) that match the specified group of selectors. The object returned is a NodeList.
Reference: https://developer.mozilla.org/en/DOM/Document.querySelectorAll
You can use querySelectorAll, and this is an example you can run in javascript console on this page.
var myList = document.querySelectorAll("a");
for (var c= 0 ; c < myList.length; c += 1) {
console.log(myList[c]);
myList[c].onmouseover= function () {alert(this)}
}
If your reference to a className is deliberate, you could use document.getElementsByClassName(), though this isn't supported by IE 8 and earlier. You could fall back on one of your other techniques for those versions. FWIW, I believe this is how jQuery does it.
You can use className - document.getElementsByClassName()
In HTML 5 you can use data attribute - document.querySelectorAll('[...]');
How do I get an element or element list by it's tag name. Take for example that I want all elements from <h1></h1>.
document.getElementsByTagName('a') returns an array. Look here for more information: http://web.archive.org/web/20120511135043/https://developer.mozilla.org/en/DOM/element.getElementsByTagName
Amendment: If you want a real array, you should use something like Array.from(document.getElementsByTagName('a')), or these days you'd probably want Array.from(document.querySelectorAll('a')). Maybe polyfill Array.from() if your browser does not support it yet. I can recommend https://polyfill.io/v2/docs/ very much (not affiliated in any way)
Use $$() and pass in a CSS selector.
Read the Prototype API documentation for $$()
This gives you more power beyond just tag names. You can select by class, parent/child relationships, etc. It supports more CSS selectors than the common browser can be expected to.
Matthias Kestenholz:
getElementsByTagName returns a NodeList object, which is array-like but is not an array, it's a live list.
var test = document.getElementsByTagName('a');
alert(test.length); // n
document.body.appendChild(document.createElement('a'));
alert(test.length); // n + 1
You could also use $$(tag-name)[n] to get specific element from the collection.
If you use getElementsByTagName, you'll need to wrap it in $A() to return an Array. However, you can simply do $$('a') as nertzy suggested.