Reputation: 124
I'm sorry, but I can't find better title for my question, but I'll try to better describe my problem. I have this code:
let pdfInvoice_sub_template = [
{text: '{i}', alignment: 'center'},
{text: 'invoices_sub-{i}-name', alignment: 'left'},
{text: 'invoices_sub-{i}-unit', alignment: 'center'},
];
temp_pdfSubTemplate = [];
for (i = 1; i <= 2; i++) {
temp_pdfSubTemplate[i] = pdfInvoice_sub_template;
jQuery.each(temp_pdfSubTemplate[i], function (key, val) {
document.write(val.text = val.text.replace(/{i}/g, i) + '</br>');
});
}
And hoping add two elements to the object, like this:
temp_pdfSubTemplate [[{ text: '1', alignment: 'center' },{ text: 'invoices_sub-1-name', alignment: 'left' },{ text: 'invoices_sub-1-unit', alignment: 'center' }], [{ text: '2', alignment: 'center' },{ text: 'invoices_sub-2-name', alignment: 'left' },{ text: 'invoices_sub-2-unit', alignment: 'center' }]]
But after run this code, I have:
1
invoices_sub-1-name
invoices_sub-1-unit
1
invoices_sub-1-name
invoices_sub-1-unit
In debug devtools I see after first iterate that pdfInvoice_sub_template have a replaced {i} with 1, but I do replace {i} in temp_pdfSubTemplate. Why is happened this way and what i must to do?
Thanks!
Here is fiddler:
https://jsfiddle.net/xf4j1qpu/1/
Thanks to @Lennholm, who suggested the correct answer (see below), the problem was solved.
The main reason is that when I declaring temp_pdfSubTemplate[i] in a loop, I do not create a new object, but refer to the original object pdfInvoice_sub_template, and as a result, manipulations in the loop are performed on the original object.
The problem has two solutions.
In addition, as suggested by @Lennholm, instead of declaring a variable with the original object, create a function whose only task is to create the object I need(see example in @Lennholm answear). Thus, when creating a variable in a loop, it will not just be a reference to the original object, but a new one will be created.
As a second solution is to move the declarations of the original object to the beginning of the loop. Thus, the desired result is also achieved. In each new loop, a new object will be created:
temp_pdfSubTemplate = [];
for (i = 1; i <= 2; i++) {
let pdfInvoice_sub_template = [
{text: '{i}', alignment: 'center'},
{text: 'invoices_sub-{i}-name', alignment: 'left'},
{text: 'invoices_sub-{i}-unit', alignment: 'center'},
];
temp_pdfSubTemplate[i] = pdfInvoice_sub_template;
jQuery.each(temp_pdfSubTemplate[i], function (key, val) {
document.write(val.text = val.text.replace(/{i}/g, i) + '</br>');
});
}
Upvotes: 1
Views: 54
Reputation: 7470
pdfInvoice_sub_template
and temp_pdfSubTemplate[i]
point to the same array. When you run temp_pdfSubTemplate[i] = pdfInvoice_sub_template
you're only copying the reference to the original array, you're not creating a copy of the array itself.
That means that whenever you change something in temp_pdfSubTemplate[i]
, that change will appear in pdfInvoice_sub_template
as well since they are the same thing.
Hence, when you do val.text = ...
you're overwriting the text
property in the original template. In the next iteration, it will have 1
instead of {i}
so the replacement fails and 1
remains.
Since you want temp_pdfSubTemplate[i]
to be a new, unique array based on the template, my suggestion is that you make a factory function that creates this for you instead of having a predefined object.
Change your code like this:
function createPdfInvoice_sub_template() {
return [
{text: '{i}', alignment: 'center'},
{text: 'invoices_sub-{i}-name', alignment: 'left'},
{text: 'invoices_sub-{i}-unit', alignment: 'center'},
];
}
temp_pdfSubTemplate = [];
for (i = 1; i <= 2; i++) {
temp_pdfSubTemplate[i] = createPdfInvoice_sub_template();
jQuery.each(temp_pdfSubTemplate[i], function (key, val) {
document.write(val.text = val.text.replace(/{i}/g, i) + '</br>');
});
}
console.log(temp_pdfSubTemplate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Upvotes: 2