For a JQuery plugin that I am trying to write I would like to store a local variable that whose scope is limited to the HTML identified by the selector. In the basic example below an HTML page has two form elements, I select on each form element separately and inside each instance I want to have the count of the number of text elements the form contains. In the example below “_elements” always contains the number of text input elements for last selector called. Now I think this is because of Javascript’s block level scope and closure, but not sure how to implement it. Could somebody please show me the error of my ways.
Please don’t suggest different ways of doing this (i.e. not storing the variable at all, always selecting the count of the matching elements directly – I know that would work but this is just a simplified example of the problem I’m having with local variables
<html>
<head>
<script language="javascript" src="jquery-1.4.4.min.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript">
(function ($) {
var methods = {
Setup: function (options) {
if ($(this).length == 0)
throw new Error("AutoSave() selector did not find required element");
if ($(this).length > 1)
throw new Error("AutoSave() is not designed to handle a selector that matches two or more elements!");
_elements = $('INPUT[TYPE=TEXT]', this)
_elements.length;
return this;
},
NumOfElements: function (options) {
alert(_elements.length);
return this;
}
};
$.fn.autoSave = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.Setup.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.AjaxClickEvent');
}
};
})(jQuery);
</script>
</head>
<body>
<form method="post" action="" id="myForm" name="myForm">
<input type="text" id="txt1" name="txt2" />
<input type="submit" id="submit" name="submit" />
</form>
<form method="post" action="" id="myForm2" name="myForm2">
<input type="text" id="Text1" name="Text1" />
<input type="text" id="Text2" name="Text2" />
<input type="submit" id="submit1" name="submit1" />
</form>
<script>
$(document).ready(function () {
$("#myForm").autoSave();
$("#myForm").autoSave('NumOfElements'); // Shows 1
$("#myForm2").autoSave();
$("#myForm2").autoSave('NumOfElements'); // Shows 2
$("#myForm").autoSave('NumOfElements'); // Shows 2 (should be 1)
});
</script>
</body>
</html>
OK so your code is fine, you’re not crazy. The problem is that
thisin the methods.Setup function is not the jQuery object/html node. It is the methods singleton. So you are always modifying the same _elements – hence 2 in the last example.The solution is to add:
And then when it all gets instantiated:
Then change the
thiscalls in your methods to reference methods.my_form. Then you will have the appropriate object reference to the DOM. (I would also suggest storing _elements on the HTML node in the DOM and not “out in the ether” – usedatahttp://api.jquery.com/data/)