1

Introduction:

Please bear in mind I know why my solution doesn't work, and my question is how to make it working, with current code or in a completely different way, if possible.

Also please bear in mind this is not a duplicate of In the Proxy handler, how to distiguish getting a property (var) vs calling a method? or How to get function arguments in a Proxy handler although might sound similar.

After all these precautions:

I'm trying to make a "selector", similar to the one known from jquery, but using es6' querySelectorAll and the Proxy object.

I want to use Proxy, because I want to then call mySelector('div').style = 'color:red' - in such a way, that I don't want to add 'style' property - I don't even want to know in advance such a thing exists - I want to use the existing style property (in HTMLElement)

I also want to trap method calls, like mySelector('div').setAttribute (...);

Current almost working solution:

Here, function yes returns a Proxied Yes object. In there I trap 'get' and 'set'. This works fine with:

yes('.allDivs').setAttribute('style','color:red');

yes('.allDivs').style = 'color:blue';

But this does not work:

yes('.allDivs').style.color = 'green';

Code:

Example HTML:

<div class = 'allDivs'>
 blah1 
</div>

<div class = 'allDivs'>
 blah2
</div>

Javascript:

(function(window) {

  class Yes {

      constructor(selector){
        this.length = 0;
        this.nodes  = [];
        if(typeof selector === 'string' && selector !== '') {
          this.nodes = Array.from(document.querySelectorAll(selector));
        }

        //This is we can access the object with [index]:
        if (this.nodes.length) {
          this.length = this.nodes.length;
          for (var i = 0; i < this.nodes.length; i++) {
            this[i] = this.nodes[i];
          }
        }
      }

      //methods:
      forEach (elem) {this.nodes.forEach (elem);return this;}

      //traps:  

      //target here is *we* - the Yes instance (this), and prop is (string) property being called, a property or method
      get (target, prop) {
        console.log('::get called, for prop: ', prop);
        return function(...args) {
            target.forEach((elem) => {
                if(typeof elem[prop] === 'function'){
                    elem[prop](...args);
                }
            });        

        }        
     }

    set (target, prop, value) {
        console.log('::set called, for prop, val:: ', prop, value);
        target.forEach((elem) => {
            if(typeof elem[prop] !== 'function'){
                elem[prop] = value;
            }
        });            

     }
  }

  /////////
  //End of class Yes definition

  function yes (selector){
    let yInstance = new Yes(selector);
    return new Proxy(yInstance, yInstance);
  }

  //
  Yes.fn = Yes.prototype;
  window.yes = yes;

  //E.fn.forEach = function (elem) {this.nodes.forEach (elem);return this;}



})(window);

//tests:

//These work fine:

//yes('.allDivs').setAttribute('style','color:red');//OK
//yes('.allDivs').style = 'color:blue';//OK

//This does not:
yes('.allDivs').style.color = 'green';//NOT OK

Working code: https://jsfiddle.net/kpion/5wy9uaqL/

Now, I know why it doesn't work, JS calls 'get' because it wants to read the .style property. I would love to know how to do what I want to accomplish.

Notice, that I can't just return one 'div' HTMLElement, because I want to make the changes in the whole array of elements (hence the loop in the get/set handlers).

konrados
  • 1,047
  • 8
  • 21
  • Just some slight help in a completely different way build the class to accept a ```style.color``` attrinbute and for all other ones as you want, then translate them from ```style.color = 'blue'``` => ```style ='color:blue'``` and all other ones as you want. Build them seperately, if you have to. I barely know Js classes that's why I have not even tested it. Hope this helped a little? – surge10 Apr 29 '18 at 23:27
  • @surge10 - thanks, but no, as I said, I don't want to implement "in advance" any properties or methods, known from HTMLElement / Element / Node - there are too many of them, besides the entire concept is to have a very **small** 'selector' helper:) – konrados Apr 29 '18 at 23:30
  • 1
    I guess you could further checking the `get` trap's value after you've found that it isn't a function to see if it's an object, and if so, return it wrapped in its own Proxy. I don't know what kind of issues you'll run into though. It may be better/safer to forgo some of the convenience at that level, and manually check for the `style` or `classList` or the few other known properties that'll need special handling, and perform the appropriate action for each. –  Apr 30 '18 at 00:41
  • @CrazyTrain - OK, thank you very much! Now let me play with those options and I'll be back! – konrados Apr 30 '18 at 01:04
  • 1
    Sounds good. But in all honesty, I spent a lot of time thinking about this a while back, and came to the conclusion that between `.forEach` and arrow functions, the syntax was plenty short, and simplicity, along with the advantage of using a totally native API, won out. Not to be dismissive, because using Proxy is an interesting approach. But that's the conclusion I arrived at. I'll check back tomorrow to see how things are looking. Good luck! –  Apr 30 '18 at 01:16
  • @CrazyTrain - hello again! I hope you won't be angry at me for pinging you?:) Here is what I got so far, and it seems it works fine, at least with the basic tests: https://jsfiddle.net/kpion/g1jw8azc/ (the thing related to my question is on this line: `yes('.allDivs').style.color = 'green';//OK!` ). Although... the code starts becoming bigger than I initially hoped it will be o.O – konrados Apr 30 '18 at 05:32
  • 1
    No problem. Just a couple thoughts as I look through. In the constructor, you should probably add a check for `instanceof HTMLCollection` alongside `instanceof NodeList`, since that's the other element list you'll encounter. You could do `class Yes extends Array {...` to get all the array methods, like `.forEach` for free. Looks nice though. Not really all that much code overall. –  Apr 30 '18 at 11:35

0 Answers0