0

I am trying to read 4 files into an array of objects. However, the object value in the array are all the last object. I would like to know what wrong I did for this behavior.

Code (the code has been simplified, so it may not make good sense):

import * as fs from "fs";

interface axObj {
    id: String;
    name: String;
    body: String;   
};
const logger = console;
const mypath = "/Users/autorun/Documents/Projects/Axway/Projects/axDeploy/data/rtczip/PD_only/";
const files:String[] = [
    "PD.DEVOPS.TEST.1.FS.json",
    "PD.DEVOPS.TEST.1.SFTP.json",
    "PD.DEVOPS.TEST.1.json",
    "PD.DEVOPS.TEST.1_AS2.json"
];

function doJobsSeqCall() {

    var pdObj: axObj = {
        id: "",
        name: "PD.Object",
        body: ""
    };
    var pdObjArray: axObj[] = [];

    var i = 0;
    var data: string = "";
    for (var file of files) {
        logger.debug("\nReading file: " + mypath + file);
        const data = fs.readFileSync(mypath + file, "utf8");
        if (!data) {
            throw "No data to post";
        }
        pdObj.id = String(i + 1);
        pdObj.body = data;
        pdObj.name = file;
        pdObjArray.push(pdObj);

        //Everything is correctly set here.
        logger.debug("Setting up axObj [" + pdObjArray[i].id + "]");
        logger.debug("Data file is valid with size: [" + pdObjArray[i].body.length + "]  file: [" + pdObjArray[i].name + "]");

        i++;
    }

    //Right after the for loop. This checking showed the last item was populated to all other array items which I don't understand at all.
    logger.debug("\n\nChecking pdObjArray Content");
    i = 1;
    for (let iAxObj of pdObjArray) {
        console.log("axSeqCall index: [" + i++ + "] name: [" + iAxObj.name + "]");
    }
};

try {
    doJobsSeqCall();
} catch (err) {
    logger.error(`Error: ${err}`);
    process.exit(-1);
};

Result in the log:

Reading file: /Users/autorun/Documents/Projects/Axway/Projects/axDeploy/data/rtczip/PD_only/PD.DEVOPS.TEST.1.FS.json
Setting up axObj [1]
Data file is valid with size: [754]  file: [PD.DEVOPS.TEST.1.FS.json]

Reading file: /Users/autorun/Documents/Projects/Axway/Projects/axDeploy/data/rtczip/PD_only/PD.DEVOPS.TEST.1.SFTP.json
Setting up axObj [2]
Data file is valid with size: [1625]  file: [PD.DEVOPS.TEST.1.SFTP.json]

Reading file: /Users/autorun/Documents/Projects/Axway/Projects/axDeploy/data/rtczip/PD_only/PD.DEVOPS.TEST.1.json
Setting up axObj [3]
Data file is valid with size: [1507]  file: [PD.DEVOPS.TEST.1.json]

Reading file: /Users/autorun/Documents/Projects/Axway/Projects/axDeploy/data/rtczip/PD_only/PD.DEVOPS.TEST.1_AS2.json
Setting up axObj [4]
Data file is valid with size: [874]  file: [PD.DEVOPS.TEST.1_AS2.json]


Checking pdObjArray Content
axSeqCall index: [1] name: [PD.DEVOPS.TEST.1_AS2.json]
axSeqCall index: [2] name: [PD.DEVOPS.TEST.1_AS2.json]
axSeqCall index: [3] name: [PD.DEVOPS.TEST.1_AS2.json]
axSeqCall index: [4] name: [PD.DEVOPS.TEST.1_AS2.json]

Issue:

I don't expect all of the names are [PD.DEVOPS.TEST.1.AS2.json] in the "Checking pdObjArrary Content]. I expect all of the 4 different file names such as "PD.DEVOPS.TEST.1.FS.json", "PD.DEVOPS.TEST.1.SFTP.json", "PD.DEVOPS.TEST.1.json", "PD.DEVOPS.TEST.1_AS2.json" there.

Please help and assist.

Autorun
  • 319
  • 2
  • 8
  • 20
  • If you are working in Typescript, I strongly suggest you start using `let` and `const` and avoiding `var`. – crashmstr Apr 29 '19 at 17:52

3 Answers3

1
for (var file of files) {
    var pdObj: axObj = {
        id: "",
        name: "PD.Object",
        body: ""
    };

...
}

Please declare variable pdObj in for loop.

Why?:
if pdObj outside for loop,

pdObj = ...
pdObjArray.push(pdObj);

Above code means: append same reference variable pdOjb to pdObjArray.
So, pdObjArray contains same reference array
This means shows only last value.

But, if pdObj inside for loop, pdObj is created every for loop, so, different reference object is appended to pdObjArray.


Or you can use Object clone before pdObjArray.push(pdObj);
pdObjArray.push(JSON.parese(JSON.stringfy(pdObj)));
What is the most efficient way to deep clone an object in JavaScript?

Wang Liang
  • 4,244
  • 6
  • 22
  • 45
  • Thanks King. The code works after I moved the var pdObj inside the for loop. Would you please explain the dffierence and why it didn't work if I declare the var outside the for loop? Appreciated the help. – Autorun Apr 29 '19 at 17:32
  • Thanks so much King. – Autorun Apr 29 '19 at 20:16
1

for (const file of files) or for (let file of files)

You can't use the var keyword in the for loop if you have to access the file inside asynchronous call. It won't capture the exact value of file.

Please try to change the var in the first for loop inside doJobsSeqCall function and try it again.

  • Thanks Rannie. After changing the 'var' to 'let' in the for loop, i.e. for (let file of files), it works. Would you please elaborate why 'var' not working? – Autorun Apr 29 '19 at 17:36
0

As files is an array of string, you can try to do foreach and then do all the logic in it.

files.forEach(file => { //logic here })

check out the example on Mozilla's site https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach