How do I parse the results of a querySelectorAll selector engine & allow method chaining?
css, css-selectors, html, javascript
Solution
I want to use it like this...:
$("div").innerHTML='It works!';
...not like this...:
$("div")[0].innerHTML='It works only on the specified index!';
It sounds like you want to have assigning to `innerHTML` on your set of results assign to the `innerHTML` of all of the results.
To do that, you'll have to use a function, either directly or indirectly.
Directly:
var $ = function(selector, node) { // Selector engine
var selector = selector.trim(),
node = node || document.body,
rv;
if (selector != null) {
rv = Array.prototype.slice.call(node.querySelectorAll(selector), 0); }
rv.setInnerHTML = setInnerHTML;
}
return rv;
}
function setInnerHTML(html) {
var index;
for (index = 0; index < this.length; ++index) {
this[index].innerHTML = html;
}
}
// Usage
$("div").setInnerHTML("The new HTML");
There, we define a function, and we assign it to the array you're returning as a property. You can then call that function on the array. (You might want to use `Object.defineProperty` if it's available to set the `setInnerHTML` property, so you can make it non-enumerable.)
Indirectly (requires an ES5-enabled JavaScript engine):
var $ = function(selector, node) { // Selector engine
var selector = selector.trim(),
node = node || document.body,
rv;
if (selector != null) {
rv = Array.prototype.slice.call(node.querySelectorAll(selector), 0); }
Object.defineProperty(rv, "innerHTML", {
set: setInnerHTML
});
}
return rv;
}
function setInnerHTML(html) {
var index;
for (index = 0; index < this.length; ++index) {
this[index].innerHTML = html;
}
}
// Usage
$("div").innerHTML = "The new HTML";
There, we use `Object.defineProperty` to define a setter for the property.
In the comments below you say
I have a few prototypes that work when individually attached to the $ function. Example: `$('div').makeClass('this');` They do not work when they are chained together. Example: `$('div').makeClass('this').takeClass('that');`
To make chaining work, you do `return this;` from each of the functions (so the end of `makeClass` would do `return this;`). That's because when you're chaining, such as `obj.foo().bar()`, you're calling `bar` on the return value of `foo`. So to make chaining work, you make sure `foo` returns `this` (the object on which `foo` was called).
Problem
SIMPLIFIED EXAMPLE CODE: ``` var $ = function(selector, node) { // Selector engine var selector = selector.trim(), node = node || document.body; if (selector != null) { return Array.prototype.slice.call(node.querySelectorAll(selector), 0); } } } ``` I want to use it like this...: ``` $("div").innerHTML='It works!'; ``` ...not like this...: ``` $("div")[0].innerHTML='It works only on the specified index!'; ``` ...or this: ``` for(i=0;i<$('div');i++) { $("div")[i].innerHTML='It works great but it's ugly!'; } ``` This is as close as I got. I would like chaining to work and for it to be compatible with native methods: ``` if(!Array.prototype.innerHTML) { Array.prototype.innerHTML = function(html) { for (var i = 0; i < this.length; i++) { this[i].innerHTML = html; } } } $("div").innerHTML('It works, but it ruins method chaining!'); ``` I decided to build this engine to better learn JavaScript; It's working but I am hoping I can learn some more from the kind members of Stack Overflow. Any help would be much appreciated!