Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function return map with 0 elements in Typescript/Angular

I am new to Angular and working on a sample app, which accepts a property file as input from html, process the files and stores the values in a map using typescript. I am able to store the value in the map but not able to access the map from another component.

File-reader-component.ts

export class FileReaderComponent {
    static readFileAsMap(file: File): Map<string, string> {
        let map :Map<string, string>= new Map<string, string>();

        let fileReader = new FileReader();
        fileReader.onloadend = (e) => {
            // By lines
            let lines = fileReader.result.toString().split('\n');
            for(let line = 0; line < lines.length; line++){
                if(lines[line].startsWith('#') || 
                    lines[line].startsWith('//') ||
                    ! lines[line].includes('=') ) {
                    // invalid line - ignoring it
                    continue;
                }
                let lineArr = lines[line].split('=');
                let key = lineArr[0].trim();
                let value = lineArr[1].trim();

                map.set(key, value);
                // not checking duplicate keys to let override the config
            }
        };

        fileReader.readAsText(file);
        console.log(map);
        return map;
    }
}

In the above file, console.log(map) works fine. But when we call this method in another component(as below) it returns map with 0 elements.

let config: Map<string, string> = FileReaderComponent.readFileAsMap(configFile);
like image 416
Vazid Avatar asked Apr 02 '26 00:04

Vazid


1 Answers

Well first of all, the reason it returns map with 0 elements is because onloadend is called asynchronously. readAsText is itself an asynchronous thing, and when it's done it will call onloadend. There's no real guarantee (in fact it's almost certain not to happen) that it will call it before the return gets executed.

You need to handle this asynchronicity, say via a promise.

Now for the puzzler which is that console.log is non trivial, well that's the browser playing a bit of a trick on you. It console.logs a reference, by the time you look at that reference in the terminal, it has been populated, and the browser 'helpfully' shows it as populated.

To see what I mean, paste this into your terminal

function f() { 
    const x = {}; 
    console.log(x); 
    setTimeout(() => {x[1] = 2}) 
}

and invoke f(), logically you would expect to see {}. But the browser plays its tricks and you see { 1: 2 }

like image 77
Countingstuff Avatar answered Apr 03 '26 15:04

Countingstuff