So I have a simple class with few properties. Using prototyping I add few methods.These methods returns this, so I could chain tham together.
Get method finds all elements and puts into allCurrentElements, which is an array (or at least I think so). And when I use CreateElement method, it simply creates element and tries to push it to existing array allCurrentElements.
To use it, simply write var a = _h.Get('p').CreateElement('div'). And here is where I get an error Uncaught TypeError: this.allCurrentElements.push is not a function(…).
If I try to assign newly created element using index it does not throw error however, this element does not appear in the array.
var _h = (function(){
var Helper = function(){
this.allCurrentElements = [];
}
Helper.prototype.Get = function(query){
this.allCurrentElements = document.querySelectorAll(query);
return this;
}
Helper.prototype.CreateElement = function(el, attr) {
var elem = document.createElement(el);
for (var a in attr) {
elem[a] = attr[a];
}
//this.allCurrentElements[this.allCurrentElements.length] = elem;
this.allCurrentElements.push(elem);
return this;
}
return new Helper();
})();
https://jsfiddle.net/Ldp58onu/
You have to check Document.querySelectorAll() documentation https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
Returns a non-live NodeList of all the matching element nodes.
NodeList are used very much like arrays and it's tempting to invoke Array.prototype methods on them, however NodeList objects don't have any of the familiar Array methods.
So you have to iterate through NodeList something like :
Array.prototype.forEach.call(document.querySelectorAll(query), function(element){
allCurrentElements.push(element);
});
document.querySelectorAll() returns NodeList which is an Array-like object.
The problem is that NodeLists are read-only. You'd need to transform it in an array. Array.prototype.slice.call(document.querySelectorAll(query));
after that you'll be able to whatever you want.
Related
I have an array of elements which I want to maintain efficiently, adding and removing arrays of elements over time.
var myElements = $('.initial');
jquery's merge() seems perfect for adding items as it doesn't create a new array and just adds to the existing one:
$.merge(myElements, $('.to-add'));
Is there an equivalent for removing, that also modifies the array in-place? Something like:
$.exclude(myElements, $('.to-remove'));
I do actually have arrays of DOM elements, and the selectors are just used as examples.
Assuming that you're after the relative complement of b in a.
And you don't want to create additional objects while process.
The function is for both plain Array and jQuery set.
(thus used $.each, $.inArray instead of Array.prototype.forEach Array.prototype.indexOf)
I wrote a function that fits your requirement.
$.exclude = function(a,b) {
var idx;
$.each(b, function(i, val) {
while((idx = $.inArray(val, a)) !== -1) {
a.splice(idx, 1);
}
})
return a;
}
test this code here
https://jsfiddle.net/happyhj/uwd4L1dm/8/
and you can use like this.
$.exclude(myElements, $('.to-remove'));
use jquery not method,
var filtered = $(myElements).not($('.to-remove'));
You can use delete to remove an element from an array and then use $.grep to remove the empty space.
//[0] since $("#id") will be a jquery Object
//[0] will return the particular DOM element
var orgArray = [$("#merge1")[0],$("#merge2")[0],$("#merge3")[0]];
var secArray = [$("#merge4")[0],$("#merge5")[0]]
// Will merge other two values;
// jQuery merge will merge contents of
//two array into first array
var merArray = $.merge(secArray, orgArray);
// Want to remove $("#merge2");
var getIndex = merArray.indexOf($("#merge2")[0]);
if(getIndex >-1){
delete merArray[getIndex]
}
// length before filtering
$("#l1").text(merArray.length);
//Now will remove Empty Space
merArray = $.grep(merArray,function(n){
return n==0 || n
});
$("#l2").text(merArray.length);
JSFIDDLE
You are using methods that are meant for array literals. jQuery already has method add() which will return a modified jQuery object that includes the elements matching the selector
var myElements = $('.initial');
var newCollection = myElements.add('.to-add');
newCollection.not('.to-remove').doSomething();
Don't think of jQuery objects as arrays although they are array like.
Reference add()
It's not clear what your overall objective really is but most likely you can manage it with any number of filtering methods that already exist within the api
I have a some dom objects that are selected with :
var elems = document.getElementsByClassName("royal") ;
and also another objects
var collapsedElems = document.getElementsByClassName("collapsed");
my problem occured when i tried to concat elems and collapsedElems with array concat() method
elems.concat(collapsedElems)
but the return type of getElementsByClassName() is not array actually it is
object. I checked it at chrome console with typeof operator. that seems weird to me how can i combine this two group of object. ?
getElementsByClassName() returns an HTMLcollection object which is similar to an array but not really an array so you can't call array methods using the returned value.
One hack is to use Array's prorotype methods along with .call()/.apply() to pass the returned object as the context.
var elems = document.getElementsByClassName("royal") ;
var collapsedElems = document.getElementsByClassName("collapsed");
var earray = Array.prototype.slice.call(elems, 0);
var concatenated = earray.concat.apply(earray, collapsedElems) ;
console.log(concatenated)
Demo: Fiddle
It returns an HTML Collection which does things that arrays do not (such as getting live updates when the DOM changes).
If you want to get an array with elements from both collections in it, then you could:
Create an array and then populate it by looping over each of the collections and pushing each member into it (which will give you an array) or
Use document.querySelectorAll(".royal, .collapsed"); (gets a NodeList)
From the MDN:
Returns an array-like object of all child elements which have all of
the given class names. When called on the document object, the complete
document is searched, including the root node. You may also call
getElementsByClassName() on any element; it will return only elements
which are descendants of the specified root element with the given
class names.
You can try this:
function getElementsByClassName(className)
{
if (document.getElementsByClassName)
{
return document.getElementsByClassName(className);
}
else
{
return document.querySelectorAll('.' + className);
}
}
First thing's first: this isn't asking to how to turn a NodeList into an Array. This is the opposite.
For consistency's sake, I would like to create a function that returns a NodeList, just like document.querySelectorAll() does.
Here's my current code:
var toNodeList = function(arrayOfNodes){
var fragment = document.createDocumentFragment();
arrayOfNodes.forEach(function(item){
fragment.appendChild(item);
});
return fragment.childNodes;
};
However this removes the original elements from the DOM!
How can I make a NodeList in a non-destructive fashion?
You would need to clone the node.
var toNodeList = function(arrayOfNodes){
var fragment = document.createDocumentFragment();
arrayOfNodes.forEach(function(item){
fragment.appendChild(item.cloneNode());
});
return fragment.childNodes;
};
Note pass true to cloneNode to make a deep clone.
I have an Issue Here in creating my Selectors i do need to have it like exactly jquery do
in jquery in each Set Chain it returns the Array Holding the Elements results from the selector, while i achieve this phase from scripting my selectors
var Ary = [];
var Selector = function(selectorFormant){
// Some Script using querySelectorAll and pushing Elements to Ary
return Ary;
}
Ary.getByTypes=function(typesString){
//Some Script here take the elements inside the Ary and get the elements inside them with the specific types typesString and repush new elements in the Ary
return Ary;
}
Selector.prototype = Ary;
Selector.prototype.constructor = Selector;
//this script is responsible for inheritance from Ary to Selector Class
my issue here that the Developer can use the selector class in two ways
1- Selector.getByTypes('types')
or
2- Selector('selector format like jquery').getByTypes('types')
in 2 i dont have to instantiate a object to apply the inheritance i preformed becuase the method Selector return the Ary which have the Function getByTypes
but in 1 i have to instantiate a object from Selector to apply the inheritance to have the Ary members for me when i dont need the developer write the new keyword
2 I dont need that- new Selector('selector format').getByTypes('types');
any one can help please :)
It seems what you actually want is:
function Selector(sel) {
// check if the constructor was used with "new". If not, correct that:
if (! (this instanceof Selector)) return new Selector(sel);
// Notice that "this" is an empty object, inheriting from the prototype.
var els = document.querySelectorAll(sel);
for (var i=0; i<els.length; i++)
this.push(els[i]); // use the inherited method "push"
// even though this is not an actual Array instance
// Don't return anything, there's an implizit "return this;" as we used "new"
}
// Let the prototype object inherit from Array.prototype
Selector.prototype = Object.create(Array.prototype, {
constructor: {value:Selector, configurable:true} // and (re)sest constructor
});
// define "getByTypes" method for all instances:
Selector.prototype.getByTypes = function(typ) {
// Do something with "this"
…
// and for chainability return a Selector instance, either a new one or just
return this;
};
If you really need Selector.getByTypes() - something like a "class method" - you could add a (completely unrelated) function on that property, doing what you want:
Selector.getByTypes = function(typ) {
return new Selector("*").getByTypes(typ); // or anything else
};
…however, just writing Selector("button") seems easier to me if getByTypes is doing a search in the selected elements.
How about the querySelectorAll method (although only supported by newer browsers)?
https://developer.mozilla.org/en-US/docs/DOM/document.querySelectorAll
Both typeof document.querySelectorAll('a') and document.getElementsByTagName('a') is Object, so I why I can't add a method in this way:
Object.prototype.method = function(){ alert(this); }
But, this work:
a = document.getElementsByTagName('a');
a.__proto__.__proto__.method = function(){ alert(this); }
a.method();//object HTMLCollection
I thought a.__proto__ == a.constructor.prototype, does it?
Using Object.prototype is possible. However I do not recommend messing up with it.
instance_of_my_object = document.getElementsByTagName('a'); is a single instance of your Object. In this case instance_of_my_object is a NodeList.
instance_of_my_object.method = ... attaches your method or variable to this single instance of NodeList.
If you want to attach some method to all the instances of a class then you can use prototype (like this : className.prototype.myMethod = function () ...).
I found this very useful in my case:
NodeList.prototype.toArray = function() {
return Array.prototype.slice.call(this);
};
This both shows how to add a method to NodeList in this case, and how to turn them to old simple arrays and have the options of an array like concat, foreach, and so on.
You can do the same for HTMLCollection, too. Have fun :)