alzclarke
alzclarke

Reputation: 1765

how to declare a static/class variable in a jquery ui widget factory widget

Regarding the jquery ui widget factory...

What is the best way to have a static variable/class level variable that is shared amongst all instances?

e.g.

$.widget("ui.staticTest", {
    staticVar:'unchanged',
    test: function(a){
        if(a){
            this.staticVar= a;
        }
        alert(JSON.stringify(this.staticVar));
    }
});

$('#test').staticTest();
$('#parent').staticTest();

$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

in the above, if staticVar were static, $('#parent').staticTest('test'); would alert 'changed' but instead it alerts 'unchanged'.

(this code is on jsfiddle if you wanna have a play: http://jsfiddle.net/alzclarke/Sx8pJ/)

The solutions i can think of myself are ugly:

1) $('body').data('sharedVariable', myData) - this doesn't seem like good practice, what if someone or something clears the body of data 2) store it in the prototype namespace e.g. = $.ui.staticTest.prototype.staticVar = myData; this also rings alarm bells

Upvotes: 11

Views: 14531

Answers (7)

Eric Pigeon
Eric Pigeon

Reputation: 1131

Closures is your answer

(function($) {

var staticVariable = '';

$.widget('ui.newWidget', {
    options: {

    },
    _init: function() {
    }

});

})(jQuery);

staticVariable will only be available in the scope of the widget you just defined since it's wrapped up in a anonymous function that's called immediately (like you should already be doing for your jquery/jquery ui plugins.

Upvotes: 26

pettys
pettys

Reputation: 2468

You could use the general JS encapsulation pattern:

$.widget("ui.staticTest", (function() {

    staticVar:'unchanged';

    return {
        test: function(a){
            if(a){
                staticVar= a;
            }
            alert(JSON.stringify(staticVar));
        }
    };
} ()));

Fork of your jsFiddle at: http://jsfiddle.net/pettys/RwKdZ/

Pro: nothing magical going on, not messing with jQuery space at all. Con: indents your widget another level.

Upvotes: 0

brownmamba
brownmamba

Reputation: 755

//Detailed example explaining static, instance and global variables in the widget scope

$.widget("ui.staticTest", {
    //staticVar is an instance variable, regardless of what it is named as
    staticVar: 'brownMamba',

    _create: function() {

    },

    //test the static variable
    testStatic: function(a) {
        if (a) {
        //Here you're actually creating a new static variable called 
        //staticVar which is associated with the staticTest object as you assign 
        //value to it. 
            //Lemme show you what I mean with an example
            //Here it alerts 'Undefined' as 'staticVar' does not exists
            //don't confuse it with the staticVar: 'brownMamba' declared above, 
            //that one is an instance variable
            alert("Type of $.ui.staticTest.staticVar before assignment: " + typeof $.ui.staticTest.staticVar);

            $.ui.staticTest.staticVar = a; 
            //At this point it alerts the type of 'a', which in our case is  'string'            
            alert("Type of $.ui.staticTest.staticVar after assignment: " + typeof $.ui.staticTest.staticVar);

            //value of instance variable at this point
            alert("typeof this.staticVar: " + typeof this.staticVar);
            alert("Value of this.staticVar: " +  this.staticVar);
            //value of global variable at this point
            //'Undefined' as it does not exist
            alert("Type of staticVar: " + typeof staticVar); //or window.staticVar


        } else {
            alert("value of staticVar in testStatic with no argument: " + $.ui.staticTest.staticVar);
        }
    },

    //test the instance variable
    testInstance: function(a) {
        if (a) {
        //Here you're actually working with the instance variable declared above, 
        //with the value 'brownMamba' 
        //Lemme show you what I mean with an example
        //Here it alerts 'string' as 'staticVar' exists and is assigned a string
            alert("typeof this.staticVar is " + typeof this.staticVar + " and its 
value is " + this.staticVar);

            this.staticVar = a; 
            alert("typeof this.staticVar after assignment is " + typeof this.staticVar);
            alert("Value of this.staticVar after assignment is " + this.staticVar);
        } else {
            alert("value of this.staticVar in testInstance with no argument: " + this.staticVar);
        }
    },

    //test the Global variable
    testGlobal: function(a) {
        if (a) {
        /*Here you're actually creating a global variable called staticVar*/ 
            //Lemme show you what I mean with an example
            //Here it alerts 'Undefined' as 'staticVar' does not exists
            alert("Type of staticVar before assignment: " + typeof staticVar);

            staticVar = a; //creating a global variable, which will be declared 
in window scope, i.e. window.staticVar 
            //At this point it alerts the type of a, which in our case is a 'string'            
            alert("Type staticVar after assignment: " + typeof staticVar);
            alert("Value of staticVar after assignment: " + staticVar)
        } else {
            alert("value of staticVar in testGlobal with no argument: " + staticVar);
        }
    }
});

//instantiating widget
$('#test').staticTest();
//instantiating widget
$('#parent').staticTest();

$('#test').staticTest('testStatic', 'changed');
//value will be sustained as its associated to the object
$('#parent').staticTest('testStatic');

$('#test').staticTest('testInstance', 'bluemamba');
//here the value doesn't change as its an instance variable and its value is not altered
$('#parent').staticTest('testInstance');

$('#test').staticTest('testGlobal', 'bluemamba');
//here the value is still sustained as the global is created in the previous call
$('#parent').staticTest('testGlobal');

http://jsfiddle.net/hiteshubharani/z5k4E/6/

Upvotes: 0

alzclarke
alzclarke

Reputation: 1765

simple implimentation of rooster's soludion:

$.widget("ui.staticTest", {
test: function(a){
    if(a){
        $.ui.staticTest.staticVar= a;
    }
    alert(JSON.stringify($.ui.staticTest.staticVar));
}
});
$.ui.staticTest.staticVar =  'unchanged';


$('#test').staticTest();
$('#parent').staticTest();
$('#test').staticTest('test');
$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

Upvotes: 0

alzclarke
alzclarke

Reputation: 1765

actually if your variable is an object, it is automatically static... HMMMMMMMM very helpful! (not)... especially considering that variables containing primitives show the opposite behaviour. Must be something to do with the old "the pointer isn't the object" idiom.

ANYWHO...

IF YOUR VARIABLE CONTAINS AN OBJECT {} THE FOLLOWING WILL BE THE CORRECT ANSWER, OTHERWISE, SEE THE OTHER ANSWERS:

STATIC EXAMPLE:

$.widget("ui.staticTest", {
    staticVar:{val:'unchanged'},
    _create: function(){
    },
    test: function(a){
        if(a){
            this.staticVar.val= a;
        }
        alert(JSON.stringify(this.staticVar.val));
    }
});


$('#test').staticTest();
$('#parent').staticTest();

$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

http://jsfiddle.net/alzclarke/Sx8pJ/9/

NON STATIC EXAMPLE:

$.widget("ui.staticTest", {
    _create: function(){
      this.staticVar={val:'unchanged'};
    },
    test: function(a){
        if(a){
            this.staticVar.val= a;
        }
        alert(JSON.stringify(this.staticVar.val));
    }
});


$('#test').staticTest();
$('#parent').staticTest();

$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

http://jsfiddle.net/alzclarke/Sx8pJ/10/

Upvotes: 1

cllpse
cllpse

Reputation: 21727

Seems that widgets have no shared scope. Whatsoever. So what I would do is define a shared object on the jQuery UI object itself, like you propose yourself.

Note: the shared object name should reflect the widget name and namespace.

$.ui.staticShared = { color: "#fff" };

$.widget("ui.static", {
    color: function (o)
    {
        if (typeof o !== "undefined") $.ui.staticShared.color = o;

        return $.ui.staticShared.color;
    }
});

This is as clean as it gets in my eyes. And sure; there's a risk of people overriding the shared object, but it's not as if the world is going to fall apart if that happens.

If you want some sort of fail-safe/feedback on if the shared object is invalid or has been overridden, you could do a check on the object structure on the _init event.

$.widget("ui.static", {
    _init: function ()
    {
        if (typeof $.ui.staticShared === "undefined")
        {
            alert("$.ui.staticShared is required for this plug-in to run");
        }
    },
});

The _init event is fired whenever an instance is created.

Upvotes: 2

JS Mitrah
JS Mitrah

Reputation: 686

it seems like, bit misunderstanding about the "this" keyword. Here this keyword making that variable as instance specific. Try the below code.

$.widget("ui.staticTest", {
    staticVar:'unchanged',
    test: function(a){
        if(a){
            staticVar= a;
        }
        alert(JSON.stringify(staticVar));
    }
});

$('#test').staticTest();
$('#parent').staticTest();

$('#test').staticTest('test','changed');
$('#parent').staticTest('test');

Upvotes: 0

Related Questions