Hello guys I want to have something like JQuery selectors. What I mean is this:
JQuery has a selector something like this:
$("#exampleID").JQexampleMethod();
I want to have something similar for my class. for example
selector("#exampleID").MYexampleMethod();
but I can't find out how to do this. I know how to create class and define them. But can't achieve my needs. So far what I have done is this:
var class = new TestClass();
class.selector("#exampleID").MyExampleMethod();
jQuery uses the Sizzle library to evaluate the selectors.
It's not that easy to replicate jQuery because it contains of all kinds of fixes for cross-browser issues and even a whole selector library.
That said, if you disregard those issues, a simple prototype can be as follows:
var selector = function(selector) {
var res = document.querySelectorAll(selector); // fetch elements
res.myExampleMethod = function() { // add a method
return res.length;
};
return res;
};
You could use it as follows:
selector("p").myExampleMethod(); // e.g. 12
Related
I am not using jQuery, but I have one line of code that enables the $ selector shortcut, as follows:
let $ = function (id) { return document.getElementById(id); }
I would like to also add whatever code necessary so that I can use the class selector shortcut as well.
Right now I have this:
let $c = function (cl) { return document.getElementsByClassName(cl); }
And I can select elements by class with $c("some-class"), but that returns a list that I need to then cycle through.
I would like to be able to use stuff like $(".some-class").remove("some-class") - to remove the class from all elements that have it without having to have a loop cycle through the list and remove them one by one.
Could anyone point me toward the part of jQuery that does that so I can include it and not the entire library?
I tried looking through the jQuery code for the term className but there are 39 instances and I'm not sure which part I need.
The closest thing native JS has to jQuery's sizzle selector engine is querySelector() or querySelectorAll(), depending on whether you're expecting a single element to be found, or multiple.
In your example, this would be:
let $ = selector => document.querySelectorAll(selector);
I am trying to figure out how jQuery is both a function which accepts an argument and returns a value (selector -> array of elements), and also an object that can be extended with new methods:
$.fn.myMethod = function() {//do stuff}
As a company we are moving away from jQuery, because vanilla JS is so useable. However we have some jQuery plugins I wrote that we would like to keep using. I am re-writing them, but would like to keep the syntax for using them similar to how it was in JQ. I don't want to extend the Element object (element.myPlugin()) for obvious reasons, so I was thinking I would create my own wrapper like JQ. Ideally I could define the base/default function that returns an array of DOM elements like so:
const __ = function(element) {
if (typeof element === 'string') {
return document.querySelectorAll(element)
}
return [element]
}
But then later, this function could be extended with new methods:
__.myNewPlugin = function(text) {
this.forEach(el => el.innerText = text)
}
Where this is the array of DOM elements returned by the base/default function, so that later the rest of my team could use the new method like so:
__(document.querySelector('.thing')).myNewPlugin('Hi SO')
-or-
__('.thing').myNewPlugin('Hi SO')
If for some reason you think this is a bad idea, I'm happy to hear your reasoning, but please also post an example of how this is achieved. It's obviously possible (because JQ does it), so even if I decide not to go this route, I'd still like to learn how something like this could be implemented.
Is there a way to get a list of all objects using a specified plugin? I know i can add a class to each element when it's applied but i was wondering if there was an existing way...
thanks,
If you want to do this without using classes, you might want to sniff the plugin calls, like this:
var elemsCalled = []; // this will contain all elements upon which the plugin has been called
var orig = $.fn.somePlugin;
$.fn.somePlugin = function() {
elementsCalled.push(this);
return orig.apply(this, Array.prototype.slice.call(arguments)); // for chaining, as Alnitak noted
}
Now, whenever you call $.somePlugin, the element you call it on would be added to elemsCalled.
I'm trying to add simple functions to the JavaScript DOM, e.g. an addClass function, I implemented this first with the following code:
Element.prototype.addClass = function(className) {
this.className += ' ' + className;
};
However after much reading (http://perfectionkills.com/whats-wrong-with-extending-the-dom/ was good) it seems this is a terrible way to extend the DOM for a number of reasons.
The above article states:
One of the most common alternatives to this whole mess of DOM
extension is object wrappers
Which is fine, apparently the general consensus is to use Object wrappers if you want to extend the DOM. The problem is I can't find any good examples anywhere on how you actually use object wrappers to extend the DOM ...
Can anybody give me an example of how to do so? Maybe using the above code?
Object wrappers are more expensive than extensions because you need to create a new object, but they are safer.
A simple implementation that wraps only a single element could look like this:
(function() {
window.wrap = function(el) {
return new Wrapper(el);
};
function Wrapper(el) {
this.element = el;
}
Wrapper.prototype.addClass = function(cls) {
if (this.element)
this.element.className += " " + cls;
}
Wrapper.prototype.swap = function(el) {
this.element = el;
}
})();
Then you could make a new wrapper, and to be more efficient, you could reuse it with various elements.
var wrp = wrap(document.body);
wrp.addClass("foo");
wrp.swap(document.body.firstElementChild);
wrp.addClass("bar");
Another feature you could implement would be to add return this; to all the wrapper methods. That way you could chain your function calls if you like.
var wrp = wrap(document.body);
wrp.addClass("foo")
.swap(document.body.firstElementChild)
.addClass("bar");
You could also implement your wrapper to hold multiple elements at numeric indices like an Array, or better, simply hold an Array of elements.
I think that jQuery is a big example of object wrapper. Mainly you just use it like $(domElement) to get some additional functionality.
You can do sth like:
var wrapper = function(el){
return {
go: function(){
console.log('go with', el);
}
}
};
wrapper(someEl).go();
I think that to extend the native behavior in javascript is not good.
And I find another post in the same website you post extending-built-in-native-objects-evil-or-not
So I'll say that I don't like to extend the stuff javascript provide us.
I have JavaScript code that adds and removes classes using the classList object.
The code is up and working correctly as expected until I received complaints about it because it does not work in Opera and in IE8.
I don't want to use any frameworks or code libraries. I'd like to reduce to a max the code I have to change in my program so I wanted to make my own classList object and add it to the node object. I already have this code:
if (typeof(document.createElement('input').classList) == 'undefined') {
HTMLElement.prototype.classList = new function () {
this.add = function (addClass) {
this.className += addClass;
}
}
}
which, obviously, does not work.
The problem is: I can't access the HTMLElement.className of this object like this. How can I accomplish that? How can I make this object to work similar to or exactly like the original?
Mozilla has listed a classList shim here:
http://developer.mozilla.org/en/DOM/element.classList
There's quite a bit going on in the code, but looks to be what you are after.
Instead of extending the prototype you can just create a helper function that returns the values you need:
classList = function ( elem ) {
return elem.className.replace(/\s+/g,' ').split(' ');
};
Then instead of calling elem.classList you'd just call classList(elem), meaning it doesn't work exactly like the original but it returns the same data.