1

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>');
        });
}
2
  • 1
    Remove val.text = - you're overriding the original value with the placeholder. Commented Apr 23, 2022 at 19:52
  • Thank you. But I did overriding in temp_pdfSubTemplate, why is overrided in pdfInvoice_sub_template?? Аnd I need to get not just converted strings, but create object elements with values in which {i} are replaced by iteration index. But if I try to do according to your advice, I have correct strings, but then the contents of the objects remain unchanged.... Look in console jsfiddle.net/xf4j1qpu/2 So... I`m steel confused.. Commented Apr 23, 2022 at 20:19

1 Answer 1

2

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>

Sign up to request clarification or add additional context in comments.

1 Comment

ohhh!!! you save my life! Thank you vary much! At this moment I understand something about this..... and place the let pdfInvoice_sub_template at start, inside for loop. This too helped me (by the way, this can probably be added to the answer) but I still did not fully understand the reasons for this behavior. Now, thanks to you, everything is clear!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.