Peter G.
Peter G.

Reputation: 8054

RequireJS: Cannot read property of undefined in callback

My application loads html using html() method from jQuery. I'm having a problem with running a module tabs created through RequireJS in the callback function switchScreenCallback(). I tried different variants of making this and I'm not sure if the missing reference is caused by RequireJS or the callback. The error always is:

Uncaught TypeError: Cannot read property 'switchTab' of undefined

I'm looking for a solution and I can provide a fuller code example if needed. How to make sure the tabs object is not undefined?

main.js:

requirejs.config({
    paths: {
        'jquery': '//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min',
        'jqueryui': '//code.jquery.com/ui/1.11.4/jquery-ui',
        'viewObject': 'view',
        'script': 'script',
        'tabs': 'tabs',
    },
    shim: {
        jqueryui: {
            deps: ['jquery']
        },
        jquery: {
            exports: '$'
        },
        viewObject: {
            deps: ['jquery', 'jqueryui','tabs'],
            exports: 'viewObject'
        },
        tabs: {
            deps: ['jquery', 'jqueryui'],
            exports: 'tabs'
        }
    }
});
requirejs(['script']);

view.js:

define(['jquery', 'jqueryui', 'tabs'], function($,tabs) {
    console.log("tabs test 1",tabs === undefined);// returns true
    function callWhenReady(selector, callback, scope, params) {
        if ($(selector).closest('body').length) {
            callback.call(scope, params);
        }
        else {
            setTimeout(function() {
                callWhenReady(selector, callback, scope, params);
            }, 1);
        }
    }
    var viewObject = {
        switchScreenCallback: function(event) {
            console.log("ViewObject: SwitchScreenCallback",event);
            console.log("tabs test 2",tabs === undefined);// returns true
            console.log("tabs test 3",event.data.tabs === undefined);// returns true
            tabs.switchTab(event.data.tab);
            //event.data.tabs.switchTab(event.data.tab);
        },
        switchScreen: function(event) {
            $('#maincontainer').load(event.data.screen + '.html');
            callWhenReady('#' + event.data.screen, viewObject.switchScreenCallback, viewObject, event);     
        }
    }
    return {
        "viewObject": viewObject
    }
});

tabs.js:

define(['jquery', 'jqueryui'], function($) {
    var tabs = {
        switchTab: function(tab) {
            $('#tabs').tabs('select', tab);
        }
    }
    console.log("tabs created");
    return {
        "tabs":tabs
    }
});

Upvotes: 0

Views: 5122

Answers (2)

avrahamcool
avrahamcool

Reputation: 14094

Take a closer look at view.js:

define(['jquery', 'jqueryui', 'tabs'], function($,tabs) {
    ...
});

you are loading 3 dependencies, 'jquery', 'jqueryui', 'tabs' into 2 variables ($, tabs). So tabs is the result of jqueryui, which is undefined. the return value of tabs is not assign to anything.

try that instead:

define(['jquery', 'jqueryui', 'tabs'], function($, dummy, tabs) {
        ...
    });

or just change the dependency order:

define(['jquery', 'tabs', 'jqueryui'], function($, tabs) {
        ...
    });

FYI: you already declared jqueryui as a dependency for tabs (in the shim section), and he returns nothing, so i don't see any reason to call for it again in view.js (and same goes for Jquery if you don't actually use it in this code block)

Upvotes: 4

Vijay Dev
Vijay Dev

Reputation: 1114

I think this is the problem:

define(['jquery', 'jqueryui', 'tabs'], function($,tabs) {

The above code will assign $ to jquery and jqueryui to tabs

change it to:

define(['jquery', 'jqueryui', 'tabs'], function($, $ui, tabs) {

Upvotes: 1

Related Questions