SVD SVD - 1 month ago 11
React JSX Question

Programmatically adding handlers to react form handler

In trying to cut down on boilerplate code I'm trying to add handlers for common form fields to the handler object that will highlight the bad field, show some error, etc. So far I have this:

//FieldHelper.js
exports.withStandardStoreHandlers = function (storeObj, fields)
{

for(var i = 0; i < fields.length; i++)
{
var f = fields[i];
var midName = f.charAt(0).toUpperCase() + f.slice(1);

storeObj.prototype["onUpdate" + midName] = function(event) {

this[""+f] = event.target.value;
this[f+"ValidationState"] = '';
this[f+"HelpBlock"] = '';
};
}
return storeObj;
}


and then eventually I create an Alt store, that is exported thusly:

export default alt.createStore(FieldHelper.withStandardStoreHandlers(AddressStore, "firstName", "lastName", "street"));


And it actually does add the "onUpdateFirstName", "onUpdateLastName", etc. methods, but unfortunately they all use the field that was passed last. So in this example, I type some stuff into first name, but onUpdateFirstName modifies the street text field and its validation state/help block.

Clearly, the solution is to somehow make a copy of the "f" and "midName" variables so each of the dynamically created onUpdateX methods would have it's own value for them, instead of using the last available, but I just can't figure out how to do this in JavaScript. Preferably in as backwards-compatible way as possible, as this is going to be on the front end.

Answer

This is due to var in JavaScript being function scoped rather than block scoped as your code is expecting. A better explanation can be found here: http://stackoverflow.com/a/750506/368697

One solution is to make sure your f is declared inside a function scope on each iteration by using forEach:

//FieldHelper.js
exports.withStandardStoreHandlers = function (storeObj, fields)
{
    fields.forEach(function (f) {
        var midName = f.charAt(0).toUpperCase() + f.slice(1);

        storeObj.prototype["onUpdate" + midName] = function(event) {

            this[""+f] = event.target.value;
            this[f+"ValidationState"] = '';
            this[f+"HelpBlock"] = '';    
        };
    });
    return storeObj;
}