Search code examples
javascriptmethodsprototypechainingmethod-chaining

JavaScript - Understanding Method Chaining with return DOM elements


I'm trying to understand Javascript chaining with a return DOM element. I'm not sure how to do this.

This is my code:

        (function () {
            function MyQuery(selector) {
                if (!(this instanceof MyQuery)) {
                    return new MyQuery(selector);
                }

                this.nodes = document.querySelectorAll(selector);

                for (var i = 0; i < this.nodes.length; i++) {
                    this.nodes[i] = this.nodes[i];
                }

            }

            MyQuery.fn = MyQuery.prototype = {
                parent: function () {
                    return this.nodes[0].parentNode;
                },
                color: function(setColor) {
                    this.nodes[0].style.color = setColor;
                    return this;
                }
            };

            window.myQuery = window.$ = MyQuery;

        })();

Call Methods:

myQuery(".mySpan").parent(); 

// Returns .. <div>

myQuery(".mySpan").parent().color("red");

// TypeError: myQuery(...).parent(...).color is not a function

HTML:

    <div>
        This DIV has some content.
        <span class="mySpan">This is a span</span>
        more content here.
    </div>

I'm not sure why it would give me a TypeError, I have the parentNode which is the div all I want to do is set the color text of that div.


Solution

  • In order to make chainable methods available, you must not return a DOM element but rather an instance of your MyQuery class that has this method.

    function MyQuery(selector) {
        if (!(this instanceof MyQuery)) {
            return new MyQuery(selector);
        }
    
        if (Array.isArray(selector)) {
            this.nodes = selector;
        } else {
            this.nodes = [];
            if (typeof selector == "string") {
                var nodes = document.querySelectorAll(selector);
                for (var i = 0; i < nodes.length; i++) {
                    this.nodes[i] = nodes[i];
                }
            }
        }
    }
    
    MyQuery.prototype.parent = function () {
        return new MyQuery([this.nodes[0].parentNode]);
    };
    MyQuery.prototype.color = function(setColor) {
        this.nodes[0].style.color = setColor;
        return this;
    };