dmck
dmck

Reputation: 7861

Sharing variables in JavaScript Namespace

My Goal: To namespace my javascript to keep the global namespace clean.

My question: how do I share variables between methods in my JavaScript namespace?

In my example I am extending and overwriting the behaviour of the ASP.net ModalPopupExtender. I want to know how I can share the modalPopupStack variable with ModalPopupShowOverride and ModalPopupHideOverride without making it global.

Relevant code:

$(function () {
    if (Sys.Extended != undefined && Sys.Extended.UI != undefined && Sys.Extended.UI.ModalPopupBehavior != undefined) {
        MyPageMethods.ModalPopupShowOriginal = Sys.Extended.UI.ModalPopupBehavior.prototype.show;
        MyPageMethods.ModalPopupHideOriginal = Sys.Extended.UI.ModalPopupBehavior.prototype.hide;
        Sys.Extended.UI.ModalPopupBehavior.prototype.show = MyPageMethods.ModalPopupOverrides.ModalPopupShowOverride;
        Sys.Extended.UI.ModalPopupBehavior.prototype.hide = MyPageMethods.ModalPopupOverrides.ModalPopupHideOverride;
    }
});

var MyPageMethods = {

    ModalPopupShowOriginal: function () { },

    ModalPopupHideOriginal: function () { },

    ModalPopupOverrides: {

        modalPopupStack: new Array(),

        ModalPopupShowOverride: function () {

            var extender = this;
            var topElement;

            MyPageMethods.ModalPopupShowOriginal.apply(this, arguments);

            for (var x = 0; x < modalPopupStack.length; x++) {

                if ($(modalPopupStack[x].background).css("z-index") > $(extender._element).css('z-index') || $(modalPopupStack[x].popup).css("z-index") > $(extender._element).css('z-index')) {

                    if ($(modalPopupStack[x].background).css("z-index") > $(extender._element).css('z-index')) {
                        topElement = $(modalPopupStack[x].background).css("z-index");
                    }
                    else if ($(modalPopupStack[x].popup).css("z-index") > $(extender._element).css('z-index')) {
                        topElement = $(modalPopupStack[x].popup).css("z-index");
                    }

                }

            }

            if (topElement != undefined) {
                $(extender._backgroundElement).css('z-index', topElement);
            }

            modalPopupStack.push({ 'id': extender._id, 'background': extender._backgroundElement, 'popup': extender._element });

        },

        ModalPopupHideOverride: function () {
            var extender;
            MyPageMethods.ModalPopupHideOriginal.apply(this, arguments);
            extender = modalPopupStack.shift();
        }

    }

}

I'm sure there is a simple solution to this, but I'm not sure what it is.

Upvotes: 2

Views: 757

Answers (3)

Scott Sauyet
Scott Sauyet

Reputation: 50787

Make it part of the namespace, if you like. Or for more privacy, make a local closure which incorporates it and exposes the functions you want:

var MyPageMethods = {
    ModalPopupShowOriginal: function () { },
    ModalPopupHideOriginal: function () { },
    ModalPopupOverrides: (function() {
        var modalPopupStack = new Array();
        var show = function () {
            // show implementation using modalPopupStack
        };
        var hide = function () {
            // hide implementation using modalPopupStack
        };
        return {
            ModalPopupShowOverride: show,
            ModalPopupHideOverride: hide
        }
    }())
};

By the way, it's pretty rare to use new Array() these days. This is usually preferred:

        var modalPopupStack = [];

It's shorter, cleaner, and really more explicit.

Upvotes: 0

Wayne
Wayne

Reputation: 60414

You can reference that property in both methods using:

MyPageMethods.ModalPopupOverrides.modalPopupStack

That can be a little bit cumbersome, so you'd likely want to alias it inside each method, like this:

var modalPopupStack = MyPageMethods.ModalPopupOverrides.modalPopupStack;

Note that the value is still visible in the global scope (unlike in @JaredPar's answer), but its merely piggy-backing on an existing global object.

Upvotes: 1

JaredPar
JaredPar

Reputation: 754665

It sounds like you want the variables to be visible within your namespace but not outside of it. If so then try the following solution.

var MyPageMethods = (function() { 
  // This variable is local to the namespace.  It can't be accessed from 
  // the caller
  var modalPopupStack = new Array();

  // These values are available to the callers as members of MyPageMethods
  return { 
    ModalPopupShowOriginal: function () { },

    ModalPopupHideOriginal: function () { },

    ModalPopupOverrides: { ... } 
  };
})();

This pattern uses a function to establish a private function scope for local variables of the namespace. It then returns a new object which contains the members accessible outside the namespace. Those definitions occur inside the function hence they can access the namespace private data.

Upvotes: 4

Related Questions