2

I am using what I understand to be the Javascript module pattern, and jQuery.

I have an app which has a public and an admin side. Each has its own JS file, though some functionality is shared so I have extracted it to a common file. Gulp combines the common + public files into a single file for use on the public side, and the common + admin files into a single file for use on the admin side.

The public JS file includes something like:

var PublicFoo = (function () {

    var bar = function() {
        // ..
    };

    var init = function() {
        $button.on('click', Common.someCommonThing);
    };

    return {
        init: init
    };
})();

The HTML page where this code is needed fires it off like so:

<script>
PublicFoo.init();
</script>

The admin JS file includes something very similar, also defining a bar() function, and calling the same Common module function.

var AdminFoo = (function () {

    var bar = function() {
        // ..
    };

    var init = function() {
        $button.on('click', Common.someCommonThing);
    };

    return {
        init: init
    };
})();

The common JS file (shared and combined with both public and admin JS) includes something like:

var Common = (function () {

    var someCommonThing = function() {
        // Do stuff.
        // When done, I want to call bar() in the calling module.
        // This does not work, throws 'Uncaught ReferenceError: bar is not defined'
        bar();
    };

    return {
        someCommonThing: someCommonThing,
        // ...
    };
})();

From the Common module, how can I reference a function in the calling module?

I know about .caller, but apparently that is non-standard and should not be used.

I could maybe somehow pass in the name of the calling module as a parameter to Common, and reference it, but that seems ugly:

// In PublicFoo
var init = function() {
    $button.on('click', function() {
        Common.someCommonThing(PublicFoo)
    });
};

// In Common
var someCommonThing = function(callingModule) {
    // ...
    callingModule.bar();

I could also of course extract the bar() call out and do it back in the calling module, but that doesn't seem so neat either:

// In PublicFoo
var init = function() {
    $button.on('click', function() {
        Common.someCommonThing();
        bar();
    });
};

// ... and the same thing in AdminFoo

I feel like this must be JS modules 101, a basic requirement, and yet I can't seem to find anything about it, though I may be searching using the wrong terminology. Or is the reason I can't find how to do this because it should not be done this way?

How can I reference the appropriate bar() from the Common module?

Don't Panic
  • 13,965
  • 5
  • 32
  • 51

2 Answers2

1

Passing functions to other functions is very common and perfectly idiomatic JavaScript, so you could do it like this:

// In PublicFoo
var bar = function() {
    // ..
};

var init = function() {
    $button.on('click', function() {
        Common.someCommonThing(bar)
    });
};

// In Common
var someCommonThing = function(bar) {
    // ...
    bar();
};
Thomas
  • 174,939
  • 50
  • 355
  • 478
1

I know about .caller, but apparently that is non-standard and should not be used.

Also it doesn't work in your case, as the caller is the event handler and neither PublicFoo nor AdminFoo.

I could maybe somehow pass in the name of the calling module as a parameter to Common, and reference it

Yes, passing references to the thing that you want to be called is the way to go if you want someCommonThing to do different things after it has finished. Notice you really should only use such a callback when the thing is asynchronous, otherwise just returning and calling bar afterwards (like in your last snippet) is much easier.

How can I reference the appropriate bar() from the Common module?

If both bars might be loaded at once into the page, then there's no way around a parameter that references the callback.

However, that doesn't seem to be the case in your example - on one page, AdminFoo takes the role of Foo and on the other page PublicFoo takes the role of Foo.

So just reference only Foo.bar from Common! Let the respective pages fill it with the appropriate value, i.e.

var Foo = AdminFoo

on the admin page and

var Foo = PublicFoo

on the public page.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375