Binding events with jQuery to multiple elements with a for loop - javascript

So I'm working on this think where I need to generate elements and then bind events to them. Every time I generate an element I unbind and rebind the events to the generated elements with a for loop. These functions seem to trigger, but they get the wrong index (which tells the code which element to work with).
Check out the code at jsFiddle http://jsfiddle.net/6UgYe/4/
Anything modular that solves this will do. Also feel free to comment on my code. I wrote most of this last year when I had just begun with javascript.
Regards,
Akke
EDIT: Here is the solution in action: http://jsfiddle.net/nwH8Z/3/ it calculates VAT-Free prices on blur.

Change your bindEmAll function to look like this -
function bindEmAll()
{
$('#container').on('blur', 'input[id$=".5"]', function(){
$('#Errorfield').append('Current box is ' + this.id + '<br/>').append(num_format(this.value) + '<br />')
})
}
It makes all input boxes with IDs that end in '.5' append their ids and values, handled by your num_format() function, to #Errorfield. The event handler is attached to all input boxes inside #container, even if they are added dynamically.
And remove bindEmAll() from your click handler for #addTT; otherwise the event handlers will be bound as many times as you've clicked addTT, which makes things quite messy ;-)
$('#addTT').click(function() {
addTT('#container');
});
Updated fiddle here.

The problem is happening because the blur event handler is not being run until well after the loop finished. The order of execution is:
Attach event handler to blur event on item 1
Attach event handler to blur event on item 2
...some time later...
Actually invoke the blur event
By the time your event handler is invoked the value of the variable i from the loop has changed to the index of the last value, so that is what is being used in the event handler.
To get around this you can just put your code inside a closure:
(function(i) {
$('#container input#box' + i + '\\.5').unbind();
$('#container input#box' + i + '\\.5').blur(function() {
//error processing function;
$('#Errorfield').append('Current box is $(\'#container input#box' + i + '\\.5\')<br />');
});
$('#container input#box' + i + '\\.5').blur(function() {
$('#container input#box' + i + '\\.5').val(num_format($('#container input#box' + i + '\\.5').val()));
$('#Errorfield').append('Current box is $(\'#container input#box' + i + '\\.5\')<br />');
});
})(i);
I've updated your fiddle here

boxes = 1;
function num_format(input) {
//For demo purporses, we only parseInt()+5
ret = parseFloat(input) + 5;
return ret;
}
function addTT(parentElement, arg1, arg2, arg3, arg4, arg5) {
if (!arg1) {
arg1 = "";
}
if (!arg2) {
arg2 = "";
}
if (!arg3) {
arg3 = "";
}
if (!arg4) {
arg4 = "";
}
if (!arg5) {
arg5 = num_format((0.00).toFixed(2));
}
row = $('<tr></tr>').attr('id', boxes);
cell1 = $('<td class="inputcell"></td>');
cell2 = $('<td class="inputcell"></td>');
cell3 = $('<td class="inputcell"></td>');
cell4 = $('<td class="inputcell"></td>');
cell5 = $('<td class="inputcell"></td>');
input1 = $('<input></input>').attr('style', 'width:100px;').attr('id', 'box' + boxes + '.1').attr('name', 'box' + boxes + '_1').attr('type', 'text').attr('value', arg1);
input2 = $('<input></input>').attr('style', 'width:100px;').attr('id', 'box' + boxes + '.2').attr('name', 'box' + boxes + '_2').attr('type', 'text').attr('value', arg2);
input3 = $('<input></input>').attr('style', 'width:93px;').attr('id', 'box' + boxes + '.3').attr('name', 'box' + boxes + '_3').attr('type', 'text').attr('value', arg3);
input4 = $('<input></input>').attr('style', 'width:149px;').attr('id', 'box' + boxes + '.4').attr('name', 'box' + boxes + '_4').attr('type', 'text').attr('value', arg4);
input5 = $('<input></input>').attr('style', 'width:90px;').attr('id', 'box' + boxes + '.5').attr('name', 'box' + boxes + '_5').attr('type', 'text').attr('value', arg5);
$(cell1).append(input1);
$(cell2).append(input2);
$(cell3).append(input3);
$(cell4).append(input4);
$(cell5).append(input5);
$(row).append(cell1);
$(row).append(cell2);
$(row).append(cell3);
$(row).append(cell4);
$(row).append(cell5);
$('#tBoxes').append(row);
boxes++;
}
function subTT(parentElement) {
boxes = boxes - 1;
$(parentElement + ' #' + boxes).hide(0, function () {
$(parentElement + ' #' + boxes).remove();
}
);
}
function bindEmAll() {
alert(boxes);
for (var i = 1; i <= boxes - 1; i++) {
$('#container input#box' + i + '\\.5').blur(function () {
alert($(this).val());
$(this).val(num_format($(this).val()));
//$('#container input#box' + i + '\\.5').val(num_format($('#container input#box' + i + '\\.5').val()));
//$('#Errorfield').append('Current box is $(\'#container input#box' + i + '\\.5\')<br />');
});
}
}
$('#addTT').click(function () {
addTT('#container');
bindEmAll();
});
$('#subTT').click(function () {
subTT('#container');
});
$(function () { addTT('#container'); bindEmAll(); });

Here is a small example of adding new elements and process their events:
<button id="add">+</button>
<button id="remove">-</button>
<div id="holder">
</div>
.
$('#add').on('click', function () {
$('#holder').append('<p>click me!</p>');
});
$('#remove').on('click', function () {
$('#holder p:last-of-type').remove();
});
$('#holder').on('click', 'p', function () {
alert('my id is: ' + $('#holder p').index(this));
});
And you can check it out here: http://jsfiddle.net/simo/PyKDz/

Related

jqxgrid rowselect event not triggering

I am trying to get the row data when the user checks the tick on the row checkbox.
$('#jqxgrid').on('rowselect', function (event) {
var rowIndex = $('#grid').jqxGrid('getselectedrowindexes'),
rowdata;
rowdata = $("#grid").jqxGrid('getrowdata', rowIndex);
selectedRows.append(rowData);
alert("Row with bound index: " + rowIndex + " has been selected");
});
I also tried .bind instead of .on but both are not working.
This one should work:
$('#jqxgrid').on('rowclick', function (event) {
var row = event.args.rowindex;
var datarow = $("#jqxgrid").jqxGrid('getrowdata', row);
alert("Row index: " + event.args.rowindex +" has been clicked.");
//alert(datarow.first + ' ### ' + datarow.second + ' ### ' + datarow.third)
});

Div not responding to jQuery function

I have a bunch of products that will be loaded(append-ed) to the page when the user loads the page the first time. I use a $.post() call to the database and then append the data as a number of divs into a container.
$(function() {
var profile_looks = $('#profile_looks');
$.post("apples.php", function(json) {
var looks = $.parseJSON(json);
profile_looks.prepend(
(some code here)
)
}); // close $.post()
After these products are loaded, I want the products to change background color on hover.
var product_tags = $('.product_tags');
product_tags.mouseenter(function() {
$(this).css('background-color', 'white');
});
}); // close $(function()
However step 2 does not work, meaning when I mouseover the product_tags, they do not change. Why aren't the product_tags div responding to the function call?
Full code below
$(function() {
var profile_looks = $('#profile_looks');
$.post("apples.php", function(json) {
var looks = $.parseJSON(json);
var page_post = "";
$.post('oranges.php', function(products_data) {
var products_display = $.parseJSON(products_data);
for(i = 0; i < looks.length; i++) {
var fruits = products_display[i];
for(var key in fruits) {
var test = "<div class='product_tags' style='color:" + "black" + "' >" + "<span class='type' style='font-weight:600'>" + key + "</span>" + " " + "<span class='title'>" + fruits[key] + "</span>" + "</div>";
var mega = mega + test;
}; // the 2nd for-loop finishes, and re-runs the first for-loop
}; // b=0 timer loop finishes
profile_looks.prepend(
"<div class='look'>" + "<div class='look_picture_container'>" +
"<img src='" + "user_pictures/" + username_cookie + "/" + looks[i][0] + "'>" +
"<div class='heart'>" +
"<img src='" + "../function icons/hearticon black.png" + "'>" +
"<div class='heartcount'>" +
"</div>" +
"</div>" +
"<div class='product_tags_container' style='background-color:" + looks[i][3] + "' >" + mega + "</div>" +
"</div>" + // class="look_picture_container"
"<div class='post_description'>" +
looks[i][1] +
"</div>" + // class= "post_description"
"</div>"); // class="look"
var mega = "";
}
}); // for the $.post(displayproducts.php)
}) // for the $.post(displaylooks.php)
var product_tags = $('.product_tags');
product_tags.mouseenter(function() {
$(this).css('background-color', 'white');
});
product_tags.mouseleave(function() {
$(this).css('background-color', 'transparent')
});
}); // end of $(function()
It doesn't work because the elements doesn't exist yet when you try to bind the events to them.
You can use delegated events, which you bind to an existing element where the elements will end up:
profile_looks.on('mouseenter', '.product_tags', function() {
$(this).css('background-color', 'white');
}).on('mouseleave', '.product_tags', function() {
$(this).css('background-color', 'transparent')
});
Your data is arriving asynchronously, while you're creating the "hover rule" (attaching the event handlers) synchronously.
This means that when you write:
var product_tags = $('.product_tags');
product_tags.mouseenter(function() {//...
product_tags is a collection of elements that exist right after you dispatch the async POST calls. (The answer to these POSTs didn't arrive yet at this point, so the DOM you want to attach to was not generated either.)
To fix this, trigger the attaching of these mouseenter event handlers after the async answer has arrived (from the same callback you're using to work with the returned data), and you've set up the DOM you need to work with.
Note: the other answers bring up good points about delegating your event handlers via an already existing container using jQuery's .on(), which might prove to be a cleaner, more declarative solution.
As product_tags are dynamically generated elements, you need to use .on API to delegate the events for such elements. .on API
Use this
profile_looks.on({
mouseenter: function () {
$(this).css('background-color', 'white');
},
mouseleave: function () {
$(this).css('background-color', 'transparent')
}
}, '.product_tags')

Jquery to toggle one div of same class on click

function demo(){
$('.box').slideToggle('fast');
}
$(document).ready(function(){
$.getJSON( "js/JobOpenings.json", function( data ) {
var glrScrlImg = [];
$.each( data.getJobOpeningsResult, function( key, val ) {
var st = "",id,st2= "",st3="",id;
st +="<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li onclick='demo()'>" + st+val.JobSector + "<br>" + st3 + "</li>");
$('.box').hide();
});
});
});
I am reading data from a json file. The div with 'box' class is hidden. Currently this code is displaying all div on click of the li. What changes should I make to display only the div corresponding to the clicked li?
Here what we need to do is to find the .box element within the clicked li, so we need to get a reference to the clicked element.
I would use a delegated jQuery event handler with css to initially hide the element
$(document).ready(function () {
$('#newsDetails').on('click', 'li', function () {
$(this).find('.box').toggleClass('hidden');
})
$.getJSON("js/JobOpenings.json", function (data) {
var glrScrlImg = [];
$.each(data.getJobOpeningsResult, function (key, val) {
var st = "",
id, st2 = "",
st3 = "",
id;
st += "<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box hidden'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li>" + st + val.JobSector + "<br>" + st3 + "</li>");
});
});
});
with css
.hidden {
display: none;
}
Pass the control to the function and then based on your control slideToggle its respective .box
function demo(ctrl){
$(ctrl).find('.box').slideToggle('fast');
}
$(document).ready(function(){
$.getJSON( "js/JobOpenings.json", function( data ) {
var glrScrlImg = [];
$.each( data.getJobOpeningsResult, function( key, val ) {
var st = "",id,st2= "",st3="",id;
st +="<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li onclick='demo(this)'>" + st+val.JobSector + "<br>" + st3 + "</li>");
$('.box').hide();
});
});
});
Or add a class to li and attach an event handler like below instead of writing inline onclick as below:
$("#newsDetails").append("<li class="someclass"'>" + st+val.JobSector + "<br>" + st3 + "</li>");
and then instead of function demo() write this
$('#newsDetails').on('click','.someclass',function(){
$(this).find('.box').slideToggle('fast');
});
UPDATE
Method 1:
function demo(ctrl){
$('#newsDetails').find('li.box').hide('fast'); //hide all the .box
$(ctrl).find('.box').slideToggle('fast');
}
Method 2:
$('#newsDetails').on('click','.someclass',function(){
$('#newsDetails').find('li.box').hide('fast'); //hide all the .box
$(this).find('.box').slideToggle('fast');
});
UPDATE 2:
Method 1:
function demo(ctrl){
$('#newsDetails').find('li.box').not($(ctrl).find('.box')).hide('fast'); //hide all the .box
$(ctrl).find('.box').slideToggle('fast');
}
Method 2:
$('#newsDetails').on('click','.someclass',function(){
$('#newsDetails').find('li.box').not($(ctrl).find('.box')).hide('fast'); //hide all the .box except this
$(this).find('.box').slideToggle('fast');
});
You should structure your html (which is missing from the question!) so that the div and li are "connected" in some way (maybe the div is child of li, or they have same class, ecc).
Right now the line
$('.box').slideToggle('fast');
is applied to all element with class '.box' in your page. You want to be more selective there, that's where the way you structure the html comes into play.
Here's an example: http://jsfiddle.net/owe0faLs/1/

jQuery - why do 2 elements get appended when I click an icon

I've created a JSfiddle here:
basically I have a form that will allow users to input additional sections... but when I have added more than 2 units and then proceed to click on the 'plus' (+) icon I get more than 1 element created in that section... its probably something elementary, but any info will help.
Move your Click functions out of the click function
//add unit input box and increment click counter by one.
addUnit.click(function () {
unitCounter += 1;
unitElementCount = jQuery(".unit-element").length;
if (unitCounter <= 4) {
error.hide();
container.append('<table id="unit-' + unitCounter + '-div" class="create-course-table-element unit-element"><tr><td><label class="unit-label">Unit ' + unitCounter + '</label></td><td><input class="create-course-input-element unit-input" id="unit-id-' + unitCounter + '" name="unit-' + unitCounter + '" /><div id="delete-unit-' + unitCounter + '" class="ui-icon ui-icon-circle-close del-unit" title="Delete unit"></div></td></tr><tr><td align="center">Sections</td><td><div id="add-section-icon-' + unitCounter + '" class="ui-icon ui-icon-plus add-section-icon"></div></td></tr></table><div id="section-id-' + unitCounter + '-div" class="this-section"></div>');
} else if (unitElementCount == 4) {
unitCounter = 5;
error.html("");
error.fadeIn(1500);
error.append("<p class='error-message'>Note: You are only able to add 4 units to a given course. Each unit allows you to add 10 separate sections of content; therefore you may add a total of 40 different sections to a given course. If the material requires more units, you should consider dividing the course into 2 parts.</p>");
}
});
//This part has been slightly modified and moved out of the addUnit.click() function
var counterSecTwo = 0;
var counterSecThree = 0;
var counterSecFour = 0;
jQuery(document).on("click", "#add-section-icon-2",function () {
counterSecTwo += 1;
var container = jQuery("#section-id-2-div");
container.append("<p>test "+counterSecTwo+"</p>");
});
jQuery(document).on("click", "#add-section-icon-3",function () {
counterSecThree += 1;
var container = jQuery("#section-id-3-div");
container.append("<p>test "+counterSecThree+"</p>");
});
jQuery(document).on("click", "#add-section-icon-4",function () {
counterSecFour += 1;
var container = jQuery("#section-id-4-div");
container.append("<p>test "+counterSecFour+"</p>");
});
});
Here I am binding the click handlers to Document as the elements do not exist yet: you could also add the event listener when you create the actual element.
Modified fiddle: http://jsfiddle.net/vewP7/

Avoiding use of eval() to dynamically build event handlers

I'm struggling with managing dynamically built event handlers in javascript.
In several places, I build forms, or controls in which specific events (mainly mouseovers, mouse-outs, clicks) need to be handled.
The trick is that in a significant number of cases, the event handler itself needs to incorporate data that is either generated by, or is passed-into the function that is building the form or control.
As such, I've been using "eval()" to construct the events and incorporate the appropriate data, and this has worked somewhat well.
The problem is I keep seeing/hearing things like "You should never use eval()!" as well as a couple of increasingly ugly implementations where my dynamically-built event handler needs to dynamically build other event handlers and the nested evals are pretty obtuse (to put it mildly).
So I'm here, asking if someone can please show me the better way (native javascript only please, I'm not implementing any third-party libraries!).
Here's a crude example to illustrate what I'm talking about:
function CreateInput(controlName,type,activeStyle,dormantStyle,whenClicked)
{
var inp = document.createElement('input');
inp.id = controlName;
inp.type = type;
inp.style.cssText = dormantStyle;
eval("inp.onfocus = function() { this.style.cssText = '" + activeStyle + "'; }");
eval("inp.onblur = function() { this.style.cssText = '" + dormantStyle + "'; }");
eval("inp.onclick = function() { " + whenClicked + "; }");
return inp;
}
This function obviously would let me easily create lots of different INPUT tags and specify a number of unique attributes and event actions, with just a single function call for each. Again, this is an extremely simplified example, just to demonstrate what I'm talking about, in some cases with the project I'm on currently, the events can incorporate dozens of lines, they might even make dynamic ajax calls based on a passed parameter or other dynamically generated data. In more extreme cases I construct tables, whose individual rows/columns/cells may need to process events based on the dynamically generated contents of the handler, or the handler's handler.
Initially, I had built functions like the above as so:
function CreateInput(controlName,type,activeStyle,dormantStyle,whenClicked)
{
var inp = document.createElement('input');
inp.id = controlName;
inp.type = type;
inp.style.cssText = dormantStyle;
inp.onfocus = function() { this.style.cssText = activeStyle; };
inp.onblur = function() { this.style.cssText = dormantStyle; };
eval("inp.onclick = function() { " + whenClicked + "; }");
return inp;
}
...but I found that whatever the last assigned value had been for "activeStyle", and "dormantStyle" became the value used by all of the handlers thusly created (instead of each retaining its own unique set of styles, for example). That is what lead me to using eval() to "lock-in" the values of the variables when the function was created, but this has lead me into nightmares such as the following:
(This is a sample of one dynamically-built event-handler that I'm currently working on and which uses a nested eval() function):
eval("input.onkeyup = function() { " +
"InputParse(this,'ucwords'); " +
"var tId = '" + myName + This.nodeName + "SearchTable" + uidNo + "'; " +
"var table = document.getElementById(tId); " +
"if (this.value.length>2) { " +
"var val = (this.value.indexOf(',') >=0 ) ? this.value.substr(0,this.value.indexOf(',')) : this.value; " +
"var search = Global.LoadData('?fn=citySearch&limit=3&value=' + encodeURI(val)); " +
"if (table) { " +
"while (table.rows.length>0) { table.deleteRow(0); } " +
"table.style.display='block'; " +
"} else { " +
"table = document.createElement('table'); " +
"table.id = tId; " +
"ApplyStyleString('" + baseStyle + ";position=absolute;top=20px;left=0px;display=block;border=1px solid black;backgroundColor=rgba(224,224,224,0.90);zIndex=1000;',table); " +
"var div = document.getElementById('" + divName + "'); " +
"if (div) { div.appendChild(table); } " +
"} " +
"if (search.rowCount()>0) { " +
"for (var i=0; i<search.rowCount(); i++) { " +
"var tr = document.createElement('tr'); " +
"tr.id = 'SearchRow' + i + '" + uidNo + "'; " +
"tr.onmouseover = function() { ApplyStyleString('cursor=pointer;color=yellow;backgroundColor=rgba(40,40,40,0.90);',this); }; " +
"tr.onmouseout = function() { ApplyStyleString('cursor=default;color=black;backgroundColor=rgba(224,224,224,0.90);',this); }; " +
"eval(\"tr.onclick = function() { " +
"function set(id,value) { " +
"var o = document.getElementById(id); " +
"if (o && o.value) { o.value = value; } else { alert('Could not find ' + id); } " +
"} " +
"set('" + myName + This.nodeName + "CityId" + uidNo + "','\" + search.id(i)+ \"'); " +
"set('" + myName + This.nodeName + "ProvId" + uidNo + "','\" + search.provId(i)+ \"'); " +
"set('" + myName + This.nodeName + "CountryId" + uidNo + "','\" + search.countryId(i) + \"'); " +
"set('" + input.id + "','\" + search.name(i)+ \"'); " +
"}\"); " +
"var td = document.createElement('td'); " +
"var re = new RegExp('('+val+')', 'gi'); " +
"td.innerHTML = search.name(i).replace(re,'<span style=\"font-weight:bold;\">$1</span>') + ', ' + search.provinceName(i) + ', ' + search.countryName(i); " +
"tr.appendChild(td); " +
"table.appendChild(tr); " +
"} " +
"} else { " +
"var tr = document.createElement('tr'); " +
"var td = document.createElement('td'); " +
"td.innerHTML = 'No matches found...';" +
"tr.appendChild(td); " +
"table.appendChild(tr); " +
"} " +
"} else { " +
"if (table) table.style.display = 'none'; " +
"} " +
"} ");
Currently, I'm having problems getting the nested eval() to bind the ".onclick" event to the table-row, and, as you can see, figuring out the code is getting pretty hairy (debugging too, for all the known reasons)... So, I'd really appreciate it if someone could point me in the direction of being able to accomplish these same goals while avoiding the dreaded use of the "eval()" statement!
Thanks!
And this, among many other reasons, is why you should never use eval. (What if those values you're "baking" in contain quotes? Oops.) And more generally, try to figure out why the right way doesn't work instead of beating the wrong way into submission. :)
Also, it's not a good idea to assign to on* attributes; they don't scale particularly well. The new hotness is to use element.addEventListener, which allows multiple handlers for the same event. (For older IE, you need attachEvent. This kind of IE nonsense is the primary reason we started using libraries like jQuery in the first place.)
The code you pasted, which uses closures, should work just fine. The part you didn't include is that you must have been doing this in a loop.
JavaScript variables are function-scoped, not block-scoped, so when you do this:
var callbacks = [];
for (var i = 0; i < 10; i++) {
callbacks.push(function() { alert(i) });
}
for (var index in callbacks) {
callbacks[index]();
}
...you'll get 9 ten times. Each run of the loop creates a function that closes over the same variable i, and then on the next iteration, the value of i changes.
What you want is a factory function: either inline or independently.
for (var i = 0; i < 10; i++) {
(function(i) {
callbacks.push(function() { alert(i) });
})(i);
}
This creates a separate function and executes it immediately. The i inside the function is a different variable each time (because it's scoped to the function), so this effectively captures the value of the outer i and ignores any further changes to it.
You can break this out explicitly:
function make_function(i) {
return function() { alert(i) };
}
// ...
for (var i = 0; i < 10; i++) {
callbacks.push(make_function(i));
}
Exactly the same thing, but with the function defined independently rather than inline.
This has come up before, but it's a little tricky to spot what's causing the surprise.
Even your "right way" code still uses strings for the contents of functions or styles. I would pass that click behavior as a function, and I would use classes instead of embedding chunks of CSS in my JavaScript. (I doubt I'd add an ID to every single input, either.)
So I'd write something like this:
function create_input(id, type, active_class, onclick) {
var inp = document.createElement('input');
inp.id = id;
inp.type = type;
inp.addEventListener('focus', function() {
this.className = active_class;
});
inp.addEventListener('blur', function() {
this.className = '';
});
inp.addEventListener('click', onclick);
return inp;
}
// Called as:
var textbox = create_input('unique-id', 'text', 'focused', function() { alert("hi!") });
This has some problems still: it doesn't work in older IE, and it will remove any class names you try to add later. Which is why jQuery is popular:
function create_input(id, type, active_class, onclick) {
var inp = $('<input>', { id: id, type: type });
inp.on('focus', function() {
$(this).addClass(active_class);
});
inp.on('blur', function() {
$(this).removeClass(active_class);
});
inp.on('click', onclick);
return inp;
}
Of course, even most of this is unnecessary—you can just use the :focus CSS selector, and not bother with focus and blur events at all!
You don't need eval to "lock in" a value.
It's not clear from the posted code why you're seeing the values change after CreateInput returns. If CreateInput implemented a loop, then I would expect the last values assigned to activeStyle and dormantStyle to be used. But even calling CreateInput from a loop will not cause the misbehavior you describe, contrary to the commenter.
Anyway, the solution to this kind of stale data is to use a closure. JavaScript local variables are all bound to the function call scope, no matter if they're declared deep inside the function or in a loop. So you add a function call to force new variables to be created.
function CreateInput(controlName,type,activeStyle,dormantStyle,whenClicked)
{
while ( something ) {
activeStyle += "blah"; // modify local vars
function ( activeStyle, dormantStyle ) { // make copies of local vars
var inp = document.createElement('input');
inp.id = controlName;
inp.type = type;
inp.style.cssText = dormantStyle;
inp.onfocus = function() { this.style.cssText = activeStyle; };
inp.onblur = function() { this.style.cssText = dormantStyle; };
inp.onclick = whenClicked;
}( activeStyle, dormantStyle ); // specify values for copies
}
return inp;
}

Categories