To start - i don't have a full understanding of JQuery widgets. The way i see them are as objects that can hold a state and representation on their own. The examples i used for my design come from the microsoft 'SILK' project.
The problem - As i was busy creating visual elements as JQuery widgets for a new site everything went fine, untill i initialized more then 1 element with the widget. Instance variables (arrays) seemed global as opposed to everything else. So i created a simple test project to demonstrate the behaviour:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="jquery-ui-1.9.2.min.js"></script>
<script type="text/javascript">
(function ($, undefined) {
$.widget('AR.MultiQueue', {
options: {
queueName: "",
Names: [],
Wrong: [],
Right: []
},
_create: function () {
var temp = [];
for (var i = 0; i < this.options.Names.length; i++) {
console.log('pushing ' + this.options.Names[i] + ' for ' + this.options.queueName);
this.options.Wrong.push(this.options.Names[i]);
temp.push(this.options.Names[i]);
}
this.options.Right = temp;
},
Test: function () {
console.log(this.options.queueName);
for (var i = 0; i < this.options.Names.length; i++)
console.log('Name->' + this.options.Names[i]);
for (var i = 0; i < this.options.Wrong.length; i++)
console.log('Wrong->' + this.options.Wrong[i]);
for (var i = 0; i < this.options.Right.length; i++)
console.log('Right->' + this.options.Right[i]);
},
destroy: function () {
$.Widget.prototype.destroy.apply(this, arguments);
}
});
}(jQuery));
</script>
</head>
<body>
<div id="a"></div>
<div id="b"></div>
<script type="text/javascript">
(function () {
$('#a').MultiQueue({ queueName: 'a', Names: ["a"] });
$('#b').MultiQueue({ queueName: 'b', Names: ["b"] });
setTimeout(function () {
$('#a').MultiQueue('Test');
console.log('Next widget');
$('#b').MultiQueue('Test');
}, 1000);
})();
</script>
</body>
</html>
So the output I expected is for each widget to only print out the respective ("a" or "b") array string 3 times. Instead the output is:
pushing a for a
pushing b for b
a
Name->a
Wrong->a
Wrong->b
Right->a
Next widget
b
Name->b
Wrong->a
Wrong->b
Right->b
As you can see, both the widgets print out "a" AND "b" for the array that uses a direct instance variable 'push'. For now im just rewriting my widgets to use a temporary array object like the 'Right' options var in the example, but i get the feeling there is more to jQuery widgets then i can understand (as in, do i write code the way i should???)
I searched the web for this, but the only thing i can come up with is
- dont use jQuery PLUGINS as instances
- something with jQuery widgets being stored in arrays
- the fact i never really understood arrays in javascript (as the fact arrays have fixed sizes and the closest is a List<> in C#).
Anyway, i really want to know why this is happening (and if i could expect more of these suprises, this took a bit of time to find out)
Thanks
Use null
instead of []
inside the options and only start them on _create
or _init
. This happens because the array is instantiated once for that widget type (basically speaking) and kept as a reference for every new widget created. Primitive types are copied (recursively) but arrays are referenced so when jQuery copy the options the array stays the same.