Reputation: 50970
I call the following function several times after my page is loaded. The intent is to incrementally load a lot of similarly-formatted companies from the server. For each company I would like to find all the x-editable
elements and bind a success
handler function. The success handler in each case should call a refresh function passing in the name and id of this particular company.
This all more or less works -- the companies load incrementally, I'm able to find the matching x-editable
s and bind my success
function to them.
The problem is that when the page is fully loaded and I use an x-editable
to edit some data the refreshCompany()
function is executed but with the wrong company_name
and company_guid
. The name and id that appear in the Refresh. . .
console message are the same for all companies in a container, and always the last one from company list, not the one that appeared in the Load. . .
console message.
I believe one of two things may be happening:
The company_name
and company_guid
values are remaining bound to the current (ish) values in the outer scope due to closure rules I do not fully understand.
.find('.editable')
search is operating not on my newly created company-specific object but rather on the container holding all the companies (my original implementation used .append()
instead of .appendTo()
and definitely suffered from this problem).How can I modify the following code such that refreshCompany()
will be executed using the name and id values at the time the function is bound?
function loadCompanies(company_list, container_name, link_container_name) {
var searchTerm = '#' + container_name;
for (company of company_list)
{
var company_name = company.name;
var company_guid = company.id;
console.log('Load ' + company_name + ' ' + company_guid);
$.ajax(
{
url : '${fund.name}/' + encodeURIComponent( company_name ),
type : 'GET'
}
).done (
function (company_html) {
var newElement = $(company_html).appendTo('#' + container_name);
newElement.find('.editable').editable(
{
success : function (response, newValue) {
console.log('Refresh ' + company_name + ' ' + company_guid)
refreshCompany(company_name, company_guid);
}
}
);
}
);
}
}
Upvotes: 0
Views: 220
Reputation: 525
I hope this helps but it seems the problem is that by the time you get a response from the asynchronous GET request you have already looped through all of the companies in the list, so when the success method runs, company_name and company_guid are bound the last company in the list.
I think you should be able to solve this problem with a closure. Perhaps something like defining a function outside loadCompanies like :
function refreshClosure(companyName, companyGuid) {
return function () {
console.log('Refresh ' + companyName + ' ' + companyGuid)
refreshCompany(companyName, companyGuid);
}
}
...and using it in your code like this:
function loadCompanies(company_list, container_name, link_container_name) {
var searchTerm = '#' + container_name;
for (var company in company_list)
{
var company_name = company.name;
var company_guid = company.id;
// Enclose the current value of company_name and company_guid
var refreshCurrent = refreshClosure(company_name, company_guid);
console.log('Load ' + company_name + ' ' + company_guid);
$.ajax(
{
url : '${fund.name}/' + encodeURIComponent( company_name ),
type : 'GET'
}
).done (
function (company_html) {
var newElement = $(company_html).appendTo('#' + container_name);
newElement.find('.editable').editable(
{
success : function (response, newValue) {
// Invoke the function returned from the closure
refreshCurrent();
}
}
);
}
);
}
}
I also changed the for statement in case that was part of the problem. Let me know if this helps at all.
Upvotes: 1