I have a webpage which I’m writing an extension for which detects 1 or more table/div sections and I want to insert a button into each to then call a function and pass in dynamic parameters to another function. The problem I’m running into is the dynamic values are always the last in the loop even though the button IDs appear correct in the page source (dynamic). Simplified code extract below:
for (var milestone_id in all_milestones) {
milestone = all_milestones[milestone_id];
button = document.createElement("input");
button.type = "button";
button.setAttribute("id", "callout_" + milestone_id);
button.setAttribute("style", "float: right");
button.value = "Create/Edit Details";
button.onclick = function() {open_browser(award_id, milestone_id, milestone["date"], env)};
milestone["class"].appendChild(button);
}
Current behaviour – buttons are successfully injected in with unique IDs (callout_{milestone_id}) but when invoking the function (open_browser) the milestone_id is static // the last value of milestone in the array.
Desired behaviour – as above but ensuring the correct dynamic values are sent through as per the time that the button is injected into the form.
2
Answers
You are using a
for...in
loop in combination withvar
for the loop variable. This makes it a global variable and it is overwritten each iteration and not local to the loop. You cannot use that in a closure kind of way like this. Uselet
orconst
for the loop variable instead.See this MDN-Reference for more information on
for...in
See this MDN-Reference for more information on
var
See this MDN-Reference for more information on
const
See this MDN-Reference for more information on
let
Add the different variables (the variables that you used as parameters for the function) as either data-* attributes (like the
button.dataset.milestone_id
in the example) or as properties (like thebutton.award_id
in the example) on the button. If it is a number or a string you can just use the data-* attribute. If the variable is an object or an element (like a reference to a div or table) you can add it as a property.And then in the click event callback function you get the button by
e.target
and then you can access either standard attributes, data-* attributes or properties.