Skip to content
Advertisement

$(this) undefined via requirejs on bower and node

I am trying to develop an app with a modular approach using requirejs and include only as little jQuery code as possible as necessary. I have a basic SPA app o.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>jQuery Snippets</title>
    <script data-main="main-built" src="require.js"></script>
</head>
<body>
<div class="html">
    <p>this is p</p>
    <br />
    After break...
    <p>second p</p>
</div>
</body>
</html>

app.js:

define([ "jquery/core/init" ], function( $ ) {
     console.log( $(this) );
}); // not ok. Error message below:

main-built.js:483 Uncaught TypeError: Failed to set an indexed property on ‘Window’: Indexed property setter is not supported.

Replacing code within console.log with $('body') works, but $(this) or $(document) doesn’t.

Full error:

main-built.js:483 Uncaught TypeError: Failed to set an indexed property on 'Window': Indexed property setter is not supported.
    at push (<anonymous>)
    at Function.makeArray (main-built.js:483)
    at jQuery.fn.init (main-built.js:3334)
    at main-built.js:10957
    at Object.execCb (require.js:5)
    at e.check (require.js:5)
    at enable (require.js:5)
    at e.init (require.js:5)
    at a (require.js:5)
    at Object.completeLoad (require.js:5)

build.js is:

({
    baseUrl: ".",
    paths: {
        jquery: "bower_components/jquery/src/",
        sizzle: "bower_components/jquery/external/sizzle/dist/",
        require: "."
    },
    name: "app",
    out: "main-built.js"
})

Node: node r.js -o build.js optimize=none and run it on the browser.

I am expecting a browser console output:

init [Window]

I also noticed that $(‘body’) outputs: <body>...</body> in stead of:

init [body, prevObject: init(1), context: document, selector: "body"]

My setup can be easily replicated by following this 2014 post

Is there anything I am missing?

I do not want to include the whole jquery library because it is getting larger per new release. I just want to get the modules that I need. Any helpful input or recommended alternative solution is appreciated.

Thanks in advance.

Advertisement

Answer

While I can certainly change the context of $(this) by using $.call(Object, argument) or doing an Object.assign({}, object) somewhere in the code, to manipulate the $.fn.init(selector, context) of jQuery, I have decided to create an alternative Vanilla solution Framework.

And, while jQuery is worth pursuing, I have built this custom CORE jQuery support library in stead. In other words, this framework mimics everything in the jQuery syntax as shown in the minimum code example. I believe that this is also the missing manual that most developers need that is virtually impossible to search these days in the internet due to jQuery’s popularity & search ranking wars.

The goal as mentioned in the OP is to try to include only as little jQuery code as possible or implement an alternative solution with the jQuery snippet as needed because jQuery has grown so huge with newer versions and extensions and most of those code have considerable performance overhead other than the learning curve.

With this new CORE, I can easily extend support for jQuery, with $.fn.extend or $.extend or $.prototype.extend and for future use cases whenever the need arises, do another plugin for some basic routines or re-plug $(function()}) or $(document.ready()}) or implement other custom filters and jQuery-like chores, some of which I have already built and stripped off from this code such as event handlers and the $.ajax.

The good news is, we can even reuse already built favorite jQuery plugins without having to worry about compatibility issues because the power of jQuery is already in our hands! The core also preserved our favorite dot notation among others! đŸ˜€

Overall, this is very handy whenever building minimal, manageable, reusable, modular Javascript, as well as building on top of the missing Vanilla learning curve and understanding how browsers work, especially because the heart of jQuery which is the $.extend is herein preserved. Some of the mechanics of this library though (about 2% of the code), is ported from jQuery and I’m planning to build on top of this CORE for my projects without having to worry about licenses.

That said, I hope this will be helpful to some developers out there. I’m licensing this code with MIT.

(function(){
    "use strict";
    var _, context = {}, version = 1.0;
    _ = (function(selector){
        _ = function( selector, context ) {
            if(this instanceof _ == false) {
                return new _.fn.init(selector, context);
            };

            return new _.fn.init( selector, context );
        };

        _.fn = _.prototype = {
            _: version,
            constructor: _,
            length : 0
        }

        _.extend = _.fn.extend = function() {
            var target = arguments[ 0 ] || {}, options, copy,
                i = 1,
                length = arguments.length;

            // Extend _ itself if only one argument is passed
            if ( i === length ) {
                target = this;
                i--;
            }

            for ( ; i < length; i++ ) {
                if ( ( options = arguments[ i ] ) != null ) {
                    for ( name in options ) {
                        copy = options[ name ];

                        target[ name ] = copy;
                    }
                }
            }
            return target;
        };

        _.selectors = function(el){
            var elem = [];
            for(let i = 0; i<el.length; i++){
                elem.push(el[i]);
            }
            return elem;
        }

        _.prototype.self = function(){
            this.object = this;

            this.selectors = document.querySelectorAll(selector).length &&  document.querySelectorAll(selector).length == 1

                ? document.querySelector(selector)
                : document.querySelectorAll(selector).length == 0 
                    ? '' 
                    : Array.prototype.slice.call(document.querySelectorAll(selector));

                return this;
        }

        _.prototype.html = function(arg){ // return only the first element

            if(arguments.length==0)
                return this.element.innerHTML;
            else
                return this.element.innerHTML = arg;
        };

        _.prototype.text = function(arg){ // return only the first element
            return this.element.innerText;
        };

        var root_, _quickExpr = /^(?:s*(<[wW]+>)[^>]*|#([w-]+))$/,
        init = _.fn.init = function( selector, context, root ) {

            if ( !selector ) {
                return this;
            }

            root = root || root_;
            this.selector = selector;
            this.element = null;
            var self = this, el = [];

            if(arguments.length > 0){

                if(typeof selector === 'object'){

                    if(selector == document || selector == window){
                        if(selector===window) {
                            console.log(this);
                            return Array(window);
                        } else if(selector == document){
                            return _('html');
                        }

                        return _('body');
                    } else {
                        if(selector instanceof Element){

                            this.html = function(text){
                                if(arguments.length>0)
                                    return selector.innerHTML = text;
                                else 
                                    return selector.innerHTML;
                            }
                            this.children = _.map(selector);

                            return this;
                        }
                    }
                }

                switch (selector) {
                    case '<':
                    var matches = selector.match(/<([w-]*)>/);
                    if (matches === null || matches === undefined) {
                        throw 'Invalid Selector / Node';
                        return false;
                    }
                    var nodeName = matches[0].replace('<', '').replace('>', '');
                    this.element = document.createElement(nodeName);
                    break;
                    default:
                    this.element = document.querySelector(selector);
                }

                var els = document.querySelectorAll(selector);

                for (var ie = 0; ie < els.length; ie++) {
                    el.push(els[ie]);
                }

                this.children = el;
                _.prototype.elements = (typeof selector === 'object') 
                    ? new Array(selector) 
                        : document.querySelectorAll(selector);
            }

            this[0] = this.element;

            return this;
        };
        // Give the init function the _ prototype for later instantiation
        init.prototype = _.fn;
        // Initialize central reference
        // root_ = _( document ); // optional
        return _;

    })();
    _.map = function (element) {
        return Array.prototype.map.call([element], (function (node) {
            return node;
        }));
    };
    _.each = _.prototype.each = function(r, cb) {  // faster than forEach!
      for (var i = 0, l = r.length; i < l; i++) {
        cb.call(r[i], i);
      }
      return this;
    }
    window._ = _;

    window.$ === undefined && (window.$ = _); // Own the $! :D

    return _;

}).call(this);

$.extend({
    hello : function(){
        console.log('$.extending hello');
    }
});

$.hello();

$('body').extend({
    hello : function(){
        console.log('$.fn.extending hello');
        return this;
    }
}).hello();

$.fn.extend({
    find : function(el,cb){
        var context = null, collection = [], outer = this.elements;
        this ["prevObject"] = _.selectors(this.elements);
        this.selector = (this.selector + ' '+ el).toString();
        this.this = this ["prevObject"];
        if(outer.length>0)
            for(var i=0; i<outer.length; i++) {
                collection = collection.concat(Array.prototype.slice.call(outer[i].querySelectorAll(el)));
            }

        else
            collection.push(this.element.querySelectorAll(el));
        if(arguments.length>1){
            this.childName = collection[0].localName;
            this.collection = collection;
            this.parentName = this.elements[0].localName;
            context = this;
            this.context = Object.assign({}, context);
            cb.call(this.parentName, this.childName, collection);
        } else {
            this[0] = collection;
        }
        
        return this;
    }
})
<html>
<head><title>Localizing this</title>
</head>
<body>
    <div class="test">Localizing <b>$(this)</b> <i>by unlearning <b>jQuery</b></i> with <u>6.8 kb unminified custom <b>CORE</b> extensible library</u>:<br />
        <p style="color:magenta;">I want to do $('body').find('p');</p>
        <p>this is paragraph 2</p>
    </div>
    <div id="div2">
        <span>I am span</span>
        <p> I am p</p>
        <a href="#">I am link</a><br /><br />
    </div>
    <div>Importance of using <strong style="font-size: 15px; color:#333;">$(this)</strong> after finding <b style="color:purple;">p</b>:
        <pre style="color:indigo;">
            <quote style="background: #eee;">
    $(this);
    $('div').find('p', function(i,collection){
        $.each(collection, function(i){
            console.log($(this).html());
            console.log($(this).html("Success!!!"));
            console.log($(this).children[0].style);
        });
    }); 
            </quote>
        <pre>
    </div>
</body>
</html>
Advertisement