Mr. Smith
Mr. Smith

Reputation: 5558

How to pass an element to jQuery post inside a loop

I have the following code:

for (_field in _fields) {
    $.post(
        '/api/fields',
        { id: _field.id },
        function(data, _field) {
            alert(data);
        } (data, _fields[_field)
    );
}

I have to pass the _fields[_field] element to the function that returns the data from the jQuery because loses the reference to the right object during the loop. The problem is that in defining that the post function should have a _field parameter, you also have to specify a parameter for data, or data will be overwritten with _field.

Currently data returns as undefined because I have no data object defined inside the loop. I also tried passing in null, but that also just returns null. I'm looking for a way to pass the element without overwriting the data returned from the post function.

Is there any way to fix this, or is there perhaps an alternative jQuery method that can do what's needed?

Upvotes: 4

Views: 818

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074949

You want a function factory function — a function that creates a function:

for (_fieldName in _fields) {
    $.post('/api/fields',
    {
        // Unrelated, but I think this bit is wrong; shouldn't it be
        // `id: _fields[_fieldName].id` ? You're trying to use `.id` on
        // a string -- see below for a full update
        id: _fieldName.id
    },
    makeHandler(_fields[_fieldName])
    );
}
function makeHandler(field) {
    return function(data) {
        // Use `data` and `field` here
    };
}

Note that in the object initializer we're passing into $.post, we're calling makeHandler to it runs and returns the function we'll then pass into $.post. That function is then called when the $.post completes, and has access to the data argument that $.post gives it as well as the field argument to makeHandler, because it's a closure over the context of the call to makeHandler, which includes the field argument. More: Closures are not complicated


Note that in the code above, I changed your variable _field to _fieldName to be more clear: The variable in for..in loops is a string, the name of a property. See also the comment, I think you were trying to use .id in the wrong place. Here's what I think you really wanted:

for (_fieldName in _fields) {
    _field = _fields[_fieldName];
    $.post('/api/fields',
    {
        id: _field.id
    },
    makeHandler(_field)
    );
}
function makeHandler(field) {
    return function(data) {
        // Use `data` and `field` here
    };
}

Also note that if _fields is an array, you shouldn't use for..in on it without safeguards. More: Myths and realities of for..in

Upvotes: 7

Related Questions