Reputation: 1765
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
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
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
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
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
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
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
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