user759235
user759235

Reputation: 2207

Chaining in javascript plugin not working

Found a nice tutorial online to build you're own JS library/plugin here.

In my example below I have added the parents method but this isn't working proper, as a noob i have tried a lot but i cant get it to work but no result.

I' am trying to chain the methods but this is not working as the parents method is stopping the chain.

Anybody any idea on what i am doing wrong?

var X = (function () {

    var Constructor = function (selector) {
        if (!selector) return;
        if (selector === 'document') {
            this.nodes = [document];
        } else if (selector === 'window') {
            this.nodes = [window];
        } else if(typeof selector === 'string') {
            this.nodes = document.querySelectorAll(selector);
        }else{
            this.nodes = [selector];
        }
    };

    Constructor.prototype.each = function (callback) {
        if (!callback || typeof callback !== 'function') return;
        for (var i = 0; i < this.nodes.length; i++) {
            callback(this.nodes[i], i);
        }
        return this;
    };

    Constructor.prototype.addClass = function (className) {
        this.each(function (item) {
            item.classList.add(className);
        });
        return this;
    };

    Constructor.prototype.parents = function(selector) {
        var elements   = [];
        var elem       = this.nodes[0];
        var isSelector = selector !== undefined;
        while ((elem = elem.parentElement) !== null) {
            if (elem.nodeType !== Node.ELEMENT_NODE) {
                continue;
            }
            if (!isSelector || elem.matches(selector)) {
                elements.push(elem);
            }
        }
        return elements;
    };

    var init = function (selector) {
        return new Constructor(selector);
    };

    return init;

})();

X('.class').addClass('works');//works
X('.class').parents('.parent').addClass('doesnotworks');//not working

Upvotes: 2

Views: 36

Answers (2)

epascarello
epascarello

Reputation: 207511

You want to make a new instance when you return the parents so it can be chained. I had to also change your else statement to handle an array of nodes passed in.

var X = (function () {

    var Constructor = function (selector) {
        if (!selector) return;
        if (selector === 'document') {
            this.nodes = [document];
        } else if (selector === 'window') {
            this.nodes = [window];
        } else if(typeof selector === 'string') {
            this.nodes = document.querySelectorAll(selector);
        } else {
            // Added check to allow for an array to be passed in
            this.nodes = Array.isArray ? selector : [selector];
        }
    };

    Constructor.prototype.each = function (callback) {
        if (!callback || typeof callback !== 'function') return;
        for (var i = 0; i < this.nodes.length; i++) {
            callback(this.nodes[i], i);
        }
        return this;
    };

    Constructor.prototype.addClass = function (className) {
        this.each(function (item) {
            item.classList.add(className);
        });
        return this;
    };

    Constructor.prototype.parents = function(selector) {
        var elements   = [];
        var elem       = this.nodes[0];
        var isSelector = selector !== undefined;
        while ((elem = elem.parentElement) !== null) {
            if (elem.nodeType !== Node.ELEMENT_NODE) {
                continue;
            }
            if (!isSelector || elem.matches(selector)) {
                elements.push(elem);
            }
        }
        // create a new instance of your constructor with the new elements
        return new Constructor(elements);
    };

    var init = function (selector) {
        return new Constructor(selector);
    };

    return init;

})();

X('.class').addClass('works');//works
X('.class').parents('.parent').addClass('doesnotworks');//not working
.parent { border: 1px solid red; padding: 5px; }
.class { border: 1px solid purple; padding: 5px; }


.works {
  background-color: yellow;
}

.doesnotworks {
  outline: 3px dashed green;
}
<div class="parent">
  <div class="parent">
    <div class="class">foo</div>
  </div>
</div>

Upvotes: 1

Barry Michael Doyle
Barry Michael Doyle

Reputation: 10608

The issue here is that elements is an array, not an instance of Constructor.

Fix it using this:

this.nodes = elements

Upvotes: 0

Related Questions