Ericft
Ericft

Reputation: 31

Trying to make a jQuery like with multiple selectors

I try to make a very lite "jQuery like" selector, but I have problem to make it work on all classes, I tried with a for loop but because of the "return new" it brakes the loop.

JS

var $ = function(el){       
  var helpers = {
    css: function(v){
      (this.value).setAttribute('style',v);     
    },
    replace: function(v){
      (this.value).innerHTML = v;
      console.log(this.value);
    },
    append: function(v){
      (this.value).innerHTML =  (this.value).outerHTML + ' ' + v;
    }
  };
  function sel(el){ 
    this.value = document.querySelector(el);
  }
  sel.prototype = helpers;
  return new sel(el);
};

var sel1 = $('.sel1');

sel1.replace('<span>replaced</span>');
sel1.css("color:red");

HTML

<div class="sel1">test</div>
<div class="sel1">test</div>
<div class="sel1">test</div>

Upvotes: 3

Views: 171

Answers (2)

Oliver Hader
Oliver Hader

Reputation: 4202

One of the powers of jQuery is the possibility to chain commands, which is actually done by holding a reference to the initial selector query. To get the basic idea, a simple kick-start implementation could look like this:

$$$ = function(selector) {
  var Handler = function(selector) {
    var elements = document.querySelectorAll(selector);
    this.css = function(options) {
      for (var i=0; i<elements.length; i++) {
        for (var property in options) {
          elements.item(i).style[property] = options[property];
        }
      }
      return this;
    };
    this.hide = function() {
      return this.css({display: 'none'});
    };
    this.show = function() {
      return this.css({display: ''});
    };
    this.replace = function(html) {
      for (var i=0; i<elements.length; i++) {
        elements.item(i).innerHTML = html;
      };
      return this;
    };
  };
  return new Handler(selector);
};

A simple working example for the code above could look like this:

$$$('div').css({border: '1px solid red', background: 'green'}).hide().show();

Since all internal functions return the current instance (return $this), chaining calls to different actions is enabled.

Upvotes: 0

Alexis Wilke
Alexis Wilke

Reputation: 20741

You want to use the Document.querySelectorAll() to get all the matches and not just the very first one. That's what jQuery does.

Obviously, this means 'value' is not a node, instead, it's a NodeList (or null). This changes the functions because they all have to deal with a list so you have to have some form of foreach() to apply your function to each node (which, again, is what jQuery does, see the get() function as a good proof of this.)

Finally, if nothing matches, jQuery gets a null and the functions still work. This is because each function uses the foreach() function and on null, foreach() does nothing. So you'd have to implement that foreach(). Maybe something like this:

function foreach(list, func)
{
   var max, i, n;

   if(list) // make sure list is not 'null'
   {
       max = list.length;
       for(i = 0; i < max; ++i) // go through the elements
       {
           n = list[i];
           func(n);   // call user function
       }
   }
}

Then the css function would become something like this:

css: function(v)
{
  foreach(this.value, function(n) { n.setAttribute('style', v); });
}

Note: if you make the foreach() part of the helpers, make sure to use this.foreach() to call it.

Upvotes: 1

Related Questions