Issue in Creating JavaScript Selectors - javascript

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

Related

Javascript - make array of objects and understanding constructors

I know this question has been asked before, but they're always project specific and I can't find what i'm looking for.
I need an array of objects in javascript. I have declared a class as :
var svgData = {.....}
(the keyword class isn't available in esversion: 5)
and I have an array variable :
var svgContent = [];
I tried doing it like you would in C# where you would write :
svgContent[0] = new svgData();
However you would normally create a constructor for it, which as far as I can tell, doesn't exist in javascript. I have been using a function like this:
function SvgData (....) {
this.var = ...;
etc.
}
but the problem is that there is no link between this and the class, and as such I have an issue that when I try to access a variable in the array using a for loop like this:
for(var i = 0; i < length; i ++){
console.log(svgContent[i].var);
}
it returns the same number repeatedly (its just overriding itself, since the way i have done it has linked every array element to the exact same variable svgData{}.
How do I make an instance of a class (object)? And how do you link the constructor to the variable?
You could easily change your code to get what you want (as far as I understand):
function SvgData(value) {
this.var = value;
// ...
}
// use this instead of your svgData variable:
SvgData.prototype = {
// ...
}
var svgContent = [];
svgContent.push(new SvgData("value"));
Read more on JavaScript prototypes.
You should consider the fact the JavaScript is a standalone language and implement things in its own way. From your question, I understand you want an array (which is still an object in JS, just with some special properties) of objects and you want those object to be made from a template (let's say a "class").
You've mentioned that there are no constructors, since there are no classes. But the way you've used function SvgData is exactly how you can design "classes". That's called a constructor function and it's special because it has no other statements than assignments to this object and thus it implicitly returns the this object (a constructor function is any function which returns the this object).
The syntax: new SvgData is basically syntax sugar for: create a new empty object (from "new") and assign to it the this object that is returned from whatever function comes next.
function SvgData (val) {
this.var = val;
}
var myLength = 10;
var myArr = [];
for (var i = 0; i < myLength; i ++) {
myArr.push(new SvgData(i));
}
console.log(myArr);
This should do what you want it to do. You can test it here.

Cannot push element to array after using querySelectorAll

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.

Object in NodeList prototype

The prototype of some native javascript objects can be extended to include new functions (such as NodeList.prototype.forEach or NodeList.prototype.addEventListener) which I use to allow array and element-like interaction with the NodeList. So far so good, but how should I add an object to the prototype which in turn has it's own functions (to allow NodeListVar.classList.remove("class")). I have been able to make NodeListVar.classList().remove("class"), by doing the following
NodeList.prototype.classList = function(){
var _this = this;
return {
remove: function(class){
_this.forEach(function(){
this.classList.remove(class);
});
}
}
};
However I would greatly prefer the syntax to be the same as a normal element, thus more like:
NodeList.prototype.classList = {
remove: function(class){
//where *this* would be the nodeList and *not* the DOMWindow
this.forEach(function(){
this.classList.remove(class);
});
}
};
It probably isn't hard even, but I have searched google endlessly and looked through countless questions already and can't find anything usefull.
First to read: What’s wrong with extending the DOM.
You can't set objects on a prototype. All called functions will be executed in context of that static prototype object, not the NodeList itself. The object on the prototype has no reference to the current NodeList.
On normal Elements, every element has its own classList attribute, a DOMTokenList bound the element. You will need to do the same: Give every NodeList its own classLists instance. As you can't do that in the unavailable constructor, you will have to use a getter, as already demonstrated.
I don't think you should try to allow the same syntax on NodeLists as on Elements, because they are very different. But if you want to get rid of these brackets, you can install a native getter function.
function ClassLists(nl) {
... // nl references the NodeList we're bound to
}
ClassLists.prototype = ...;
Object.defineProperty(NodeList.prototype, "classLists", {
get: function() {
return this.classLists = new ClassLists(this);
}
});
Just to complement #Bergi's answer, here is a cross-browser solution:
function ClassList() {
this.nodeList;
}
ClassList.prototype = {
constructor: ClassList,
remove: function() {
console.log( this );
}
};
NodeList.prototype.classList = new ClassList();
nl.classList.remove(); // ClassList object with the `nodeList` property.
It can't be used with the same API since it's not using defineProperty, but it's cross-browser. defineProperty is only available in IE9, and is not shimmable in IE7.

How to add Nodelist/HtmlColection new method by prototype?

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 :)

Copy and extend global objects in javascript

is there a way to copy a global object (Array,String...) and then extend the prototype of the copy without affecting the original one? I've tried with this:
var copy=Array;
copy.prototype.test=2;
But if i check Array.prototype.test it's 2 because the Array object is passed by reference. I want to know if there's a way to make the "copy" variable behave like an array but that can be extended without affecting the original Array object.
Good question. I have a feeling you might have to write a wrapper class for this. What you're essentially doing with copy.prototype.test=2 is setting a class prototype which will (of course) be visible for all instances of that class.
I think the reason the example in http://dean.edwards.name/weblog/2006/11/hooray/ doesn't work is because it's an anonymous function. So, instead of the following:
// create the constructor
var Array2 = function() {
// initialise the array
};
// inherit from Array
Array2.prototype = new Array;
// add some sugar
Array2.prototype.each = function(iterator) {
// iterate
};
you would want something like this:
function Array2() {
}
Array2.prototype = new Array();
From my own testing, the length property is maintained in IE with this inheritance. Also, anything added to MyArray.prototype does not appear to be added to Array.prototype. Hope this helps.
Instead of extending the prototype, why don't you simply extend the copy variable. For example, adding a function
copy.newFunction = function(pParam1) {
alert(pParam1);
};

Categories