I'm using a plugin called datatables.js, which allows you to create tables with many built-in functions. Anyway, for it to work, there is a section where it asks you for a section called columns. I am trying to make dynamic columns, so far I have this:
var columnasTabla = [
{ data: "C_prove" },
{ data: "Descripcion" },
{ data: "Rfc_proveedor" },
{ data: "Nombre_comprador" },
];
for (var i = 0; i < sucursales.length; i++) {
var intento = i;
columnasTabla.push({
render: function (data, type, full, meta) {
return "<label><input type='checkbox' class='sucursalCheckbox' name='sucursalCheckbox' sucursalID='" + sucursales[intento] + "' checked /><span></span></label>"
}
});
}
datatables js does not allow you to directly put a checkbox as a column, but it allows you to use a function to print it. the variable sucursales
is an array containing 2 strings, "001" and "003". The idea would be that, when arranging the columns with datatables.js, the branchID should be 001 in the first column, and 003 in the second. For some reason, when I run the code, it always keeps the last index of the array, that is, they all come out with "003" in the branchID field. Why does this happen? no matter how many elements the array has, it always keeps the last one.
The problem is related to the concept of closure . Since the elements of the array are functions, and from their body they refer to the variable
intento
, the definition of these functions contains a reference to the external variableintento
, in order to be able to "close" their definition.The problem is that all the functions refer to the same variable
intento
, which is "003" at the end of the loop. Therefore, when, once the loop is finished, you try to execute any of these functions through something likecolumnasTabla[0].render()
, for example, the internal reference that this function has tointento
is resolved with the value 3, which is the value that said variable has at that moment.In other words, the variable
intento
is not evaluated in each iteration of the loop, but is simply "referenced" from the function, and that is what constitutes the closure . By the time the function associated withrender
is executed, the variableintento
will have already changed its value and will have the value that corresponds to the last iteration of the loop.To solve the problem, you have to force the variable intent to be evaluated at each iteration of the loop, rather than after the loop is finished, as part of the function definition.
One way to achieve this is to make an anonymous function that takes as a parameter the
intento
and returns as its result the function you want to bind to therender
, which already has that particular intent, and call that anonymous function on each iteration of the loop. Namely:With this trick, the reference to
intento
that there is in the internal function, refers to the parameter of the external anonymous function, and that parameter takes a different value in each iteration of the loop (we could have passed the same thingi
as a parameter and thus save ourselves thevar intento=i;
)