Javascript

How to install NodeJS 16.x LTS on Ubuntu in 1 minute

Run these shell commands on your Ubuntu computer to install NodeJS 14.x:

curl -sL https://deb.nodesource.com/setup_16.x | sudo -E bash -
sudo apt-get install -y nodejs

Instead of setup_16.x you can also choose other versions like setup_14.x. However, using this method, you can’t install multiple versions of NodeJS in parallel.

Source: Official nodesource documentation

Posted by Uli Köhler in Linux, NodeJS

How to identify the latest npm package version

You can use

npm info [package name] version | head -n1

to print just the latest package version, for example:

npm info @angular/cli version | head -n1

The head -n1 part is neccessary to suppress unwanted npm info messages. Just running the command without head -n1 :

npm info @angular/cli version

prints the following output:

12.2.6
npm notice 
npm notice New minor version of npm available! 7.21.1 -> 7.24.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v7.24.0
npm notice Run npm install -g [email protected] to update!
npm notice

I typically use the node:latest docker container instead of a local npm to find the latest version of an npm package:

docker run -it --rm node:latest npm info meshcommander version | head -n1

At the time of writing this article, the command prints

0.9.0-d

 

Posted by Uli Köhler in NodeJS

How to get size of compressed file using JSZip

In JSZip, you can get the file size of a file compressed inside a ZIP archive by first decompressing it using zip.file(...).async(...) into an ArrayBuffer and then using .byteLength to get the size of the buffer.

zip.file("filename.txt").async("ArrayBuffer").then(function(data) {
    var fileSize = data.byteLength;
    // TODO Your code goes here
})

Full example

This is based on our post on How to uncompress file inside ZIP archive using HTML5 & JSZip which reads a local file using a HTML5 file input. This example prints the file size of every file inside the ZIP archive:

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />

    <script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            var filename = fileInput.files[0].name;
            var reader = new FileReader();
            reader.onload = function(ev) {
                JSZip.loadAsync(ev.target.result).then(function(zip) {
                    zip.file("word/document.xml").async("ArrayBuffer").then(function(data) {
                        console.log("word/document.xml is", data.byteLength, "bytes long");
                    })
                }).catch(function(err) {
                    console.error("Failed to open", filename, " as ZIP file:", err);
                })
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

Example output

word/document.xml is 88369 bytes long

 

Posted by Uli Köhler in Javascript

How to list files inside a ZIP archive using JSZip

In JSZip, you can list files inside a ZIP archive using zip.fileswhich is an Object with key = filename and value = file metadata object.

JSZip.loadAsync(fileContent).then(function(zip) {
    for(let [filename, file] of Object.entries(zip.files)) {
        // TODO Your code goes here
        console.log(filename);
    }
}).catch(function(err) {
    console.error("Failed to open", filename, " as ZIP file:", err);
})

Full example

This is based on our post on How to read local ZIP in HTML5/Javascript using JSZip

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />

    <script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            var filename = fileInput.files[0].name;
            // var filesize = fileInput.files[0].size;
            var reader = new FileReader();
            reader.onload = function(ev) {
                JSZip.loadAsync(ev.target.result).then(function(zip) {
                    console.log(zip)
                }).catch(function(err) {
                    console.error("Failed to open", filename, " as ZIP file");
                })
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

 

 

Posted by Uli Köhler in Javascript

How to read a file inside a ZIP archive as string using JSZip

Want to read as an ArrayBuffer instead? Read How to read a file inside a ZIP archive as ArrayBuffer using JSZip

In JSZip, you can read a compressed file as JavaScript string using

zip.file("filename.txt").async("string").then(function(data) {
    // data is a string
    // TODO your code goes here, this is just an example
    console.log(data);
})

Full example

This is based on our post on How to uncompress file inside ZIP archive using HTML5 & JSZip which reads a local file using a HTML5 file input. You can upload any .docx file for testing:

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />

    <script src="https://unpkg.com/jszi[email protected]/dist/jszip.js" type="text/javascript"></script>
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            var filename = fileInput.files[0].name;
            var reader = new FileReader();
            reader.onload = function(ev) {
                JSZip.loadAsync(ev.target.result).then(function(zip) {
                    zip.file("word/document.xml").async("string").then(function(data) {
                        // data is a string
                        // TODO Your code goes here!
                        console.log(data)
                    })
                }).catch(function(err) {
                    console.error("Failed to open", filename, " as ZIP file:", err);
                })
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

 

Posted by Uli Köhler in Javascript

How to read a file inside a ZIP archive as ArrayBuffer using JSZip

Want to read as a string instead? Read How to read a file inside a ZIP archive as string using JSZip

In JSZip, you can read a compressed file as ArrayBuffer using

zip.file("filename.txt").async("ArrayBuffer").then(function(data) {
    // data is an ArrayBuffer
    // TODO your code goes here
})

Full example

This is based on our post on How to uncompress file inside ZIP archive using HTML5 & JSZip which reads a local file using a HTML5 file input:

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />

    <script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            var filename = fileInput.files[0].name;
            var reader = new FileReader();
            reader.onload = function(ev) {
                JSZip.loadAsync(ev.target.result).then(function(zip) {
                    zip.file("word/document.xml").async("ArrayBuffer").then(function(data) {
                        // data is an ArrayBuffer
                        // TODO Your code goes here!
                    })
                }).catch(function(err) {
                    console.error("Failed to open", filename, " as ZIP file:", err);
                })
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

 

Posted by Uli Köhler in Javascript

How to uncompress file inside ZIP archive using HTML5 & JSZip

In our previous post How to read local ZIP in HTML5/Javascript using JSZip we provided an example of how to use JSZip to list files inside a local ZIP archive using HTML5.

This post will expand upon this in order to read the content of a file compressed inside a local ZIP archive file.

In this example, we’ll read a local ZIP file using HTML5 <input type="file"> and uncompress its content. We’ll read the word/document.xml file, so you can upload any .docx file to test that.

JSZip.loadAsync(ev.target.result).then(function(zip) {
    zip.file("word/document.xml").async("ArrayBuffer").then(function(data) {
        // data is an ArrayBuffer
        // TODO Your code goes here!
    })
}).catch(function(err) {
    console.error("Failed to open", filename, " as ZIP file:", err);
})

Full example

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />

    <script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            var filename = fileInput.files[0].name;
            var reader = new FileReader();
            reader.onload = function(ev) {
                JSZip.loadAsync(ev.target.result).then(function(zip) {
                    zip.file("word/document.xml").async("ArrayBuffer").then(function(data) {
                        // data is an ArrayBuffer
                        // TODO Your code goes here!
                    })
                }).catch(function(err) {
                    console.error("Failed to open", filename, " as ZIP file:", err);
                })
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

 

 

Posted by Uli Köhler in HTML, Javascript

How to include JSZip in the browser

The JSZip documentation doesn’t make it entirely clear how to include it in the browser, i.e. which <script> tag you need to use in order to load JSZip.

Here’s the appropriate <script> tag:

<script src="https://unpkg.com/[email protected]/dist/jszip.min.js" type="text/javascript"></script>

You can also use the non-minified version which does not have minified class and object names:

<script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>

 

Posted by Uli Köhler in HTML, Javascript

How to read local ZIP in HTML5/Javascript using JSZip

In our previous post How to load local file in Javascript using HTML5 FileReader we showed how to read a local file using the HTML5 FileReader.

Based on this, it’s pretty easy to use JSZip to read a local ZIP file:

var reader = new FileReader();
reader.onload = function(ev) {
    JSZip.loadAsync(ev.target.result).then(function(zip) {
        // TODO Your code goes here. This is just an example.
        console.log(zip)
    }).catch(function(err) {
        console.error("Failed to open", filename, " as ZIP file:", err);
    })
};
reader.onerror = function(err) {
    console.error("Failed to read file", err);
}
reader.readAsArrayBuffer(fileInput.files[0]);

One example of what you can do using the JSZip object is to list the filenames inside the ZIP file:

var filename = fileInput.files[0].name;
var reader = new FileReader();
reader.onload = function(ev) {
    JSZip.loadAsync(ev.target.result).then(function(zip) {
        for(let [filename, file] of Object.entries(zip.files)) {
            console.log(filename);
        }
    }).catch(function(err) {
        console.error("Failed to open", filename, " as ZIP file:", err);
    })
};
reader.onerror = function(err) {
    console.error("Failed to read file", err);
}
reader.readAsArrayBuffer(fileInput.files[0]);

Full example

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />

    <script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            var filename = fileInput.files[0].name;
            // var filesize = fileInput.files[0].size;
            var reader = new FileReader();
            reader.onload = function(ev) {
                JSZip.loadAsync(ev.target.result).then(function(zip) {
                    console.log(zip)
                }).catch(function(err) {
                    console.error("Failed to open", filename, " as ZIP file");
                })
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

 

Posted by Uli Köhler in HTML, Javascript

How to load local file in Javascript using HTML5 FileReader

In HTML5, you can not only upload a file to a server but also process it directly in the browser using Javascript.

This post provides minimal examples of how to use FileReader to do that.

How to read a text file

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            // Example of what information you can read
            // var filename = fileInput.files[0].name;
            // var filesize = fileInput.files[0].size;
            var reader = new FileReader();
            reader.onload = function(ev) {
                var content = ev.target.result; // content is a string
                console.log("Successfully read file");
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsText(fileInput.files[0]);
        }
    </script>
</body>
</html>

How to read a binary file as ArrayBuffer

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            // Example of what information you can read
            // var filename = fileInput.files[0].name;
            // var filesize = fileInput.files[0].size;
            var reader = new FileReader();
            reader.onload = function(ev) {
                var content = ev.target.result; // content is an ArrayBuffer object
                console.log("Successfully read file");
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>

 

Posted by Uli Köhler in HTML, Javascript

Minimal leaflet.js example with Stamen terrain tiles

This minimal self-contained HTML example can serve as a good starting point for your own leaflet application. Using Stamen Terrain tiles not only provides a nice view of the physical geography but has the added advantage of not requiring any API key.

<html>
    <head>
        <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
        integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
        crossorigin=""/>
        <script src="https://unpkg.com/[email protected]/dist/leaflet.js"
        integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
        crossorigin=""></script>
        <script type="text/javascript" src="https://stamen-maps.a.ssl.fastly.net/js/tile.stamen.js?v1.3.0"></script>
        <style>
            #mymap { height: 100%; }
        </style>
    </head>
    <body>
        <div id="mymap"></div>
        <script type="text/javascript">
            var layer = new L.StamenTileLayer("terrain");
            var map = new L.Map("mymap", {
                /* Center: Munich, Germany */
                center: new L.LatLng(48.1, 11.5),
                /* Show most of western Europe */
                zoom: 6
            });
            map.addLayer(layer);
        </script>
    </body>
</html>

Look and feel of the example:

Posted by Uli Köhler in HTML, Javascript, Leaflet

Best practice Angular 11 production build command

This is the command I use to make production builds of Angular 11+ webapps:
ng build --prod --aot --build-optimizer --common-chunk --vendor-chunk --named-chunks

 

While it will consume quite some CPU and RAM during the build, it will produce a highly efficient compiled output.

Posted by Uli Köhler in Angular, Javascript

How to use child_process.exec in Koa (async/await)

First install the child-process-promise library

npm i --save child-process-promise

Then you can use it like this:

const router = require('koa-router')();
const {exec} = require('child-process-promise');

router.get('/test', async ctx => {
  const [stdout, stderr] = await exec('python myscript.py')
  const ipv6 = stdout.toString();
  ctx.body = ipv6;
});

 

Posted by Uli Köhler in Javascript

How to run TamperMonkey function after window.location.href change

When automating workflows using TamperMonkey scripts, you often have a situation where you want to run some function, then set window.location.href and after that page has loaded, run another part of your code. However, since the browser physically reloads the page, the Tampermonkey script is also reloaded – hence, your original function will stop being executed.

Fixing this is easy once you grasp the concept:

  1. Before reloading the page, we set a specific key in sessionStorage, indicating what we want to do once the page has finished loading
  2. Then we can set window.location.href
  3. On each page load, we check if the key is set and, if so, we run the appropriate function and delete the key

Note that in the TamperMonkey context, this is limited to pages that are included in the @match configuration of the script (otherwise, the script won’t be executed on the new page that is being loaded):

// ==UserScript==
// @name         TamperMonkey continuation example
// @namespace    http://tampermonkey.net/
// @version      0.1
// @author       You
// @match        https://techoverflow.net
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    const continuationKey = "_my_script_continuation_key"; // This sessionstorage key

    // Check continuation
    const continuationActions = {
        "printMsg": onPrintMsg
    };
    const _continuation = sessionStorage.getItem(continuationKey);
    if(_continuation) {
        sessionStorage.removeItem(continuationKey);
        const action = continuationActions[_continuation]
        if(action) {action();}
    }

    function onPrintMsg() {
        console.log("This is run after reloading the page");
    }

    function onAltQ() {
        console.log("Will now reload the page...");
        sessionStorage.setItem(continuationKey, "printMsg");
        window.location.href = window.location.origin + "/";
    }

    function onKeydown(evt) {
        // Use https://keycode.info/ to get keys
        if (evt.altKey && evt.keyCode == 81) {
            onAltQ();
        }
    }
    document.addEventListener('keydown', onKeydown, true);
})();

 

Posted by Uli Köhler in Javascript

How to go to URL within same domain in Javascript

In order to go to an URL relative to the current domain name in Javascript, use window.location.origin like this:

window.location.href = window.location.origin + "/myurl"
Posted by Uli Köhler in Javascript

Minimal TamperMonkey template for keypress-triggered events

This template allows you to build your own TamperMonkey scripts that react on keypresses on a specific page.

This script shows an alert message when you press Alt+Q.

// ==UserScript==
// @name         TamperMonkey keypress example
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://techoverflow.net/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    function onAltQ() {
        alert("Alt Q pressed!");
    }

    function onKeydown(evt) {
        // Use https://keycode.info/ to get keys
        if (evt.altKey && evt.keyCode == 81) {
            onAltQ();
        }
    }
    document.addEventListener('keydown', onKeydown, true);
})();

 

Posted by Uli Köhler in Javascript

How to emulate Page up / Page down key in Puppeteer

To emulate a keypress to the Page up key in Puppeteer, use

await page.keyboard.press("PageUp");

To emulate a keypress to the Page down key in Puppeteer, use

await page.keyboard.press("PageDown");

 

Posted by Uli Köhler in Javascript, NodeJS, Puppeteer

How to fix Angular 9 @ViewChild Expected 2 arguments, but got 1: An argument for ‘opts’ was not provided.

Problem:

You are trying to compile your Angular 9.x application, but you see an error message like

app/my-component/my-component.component.ts:24:4 - error TS2554: Expected 2 arguments, but got 1.

24   @ViewChild(MyOtherComponent) myOtherComponent: MyOtherComponent;
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  ../node_modules/@angular/core/core.d.ts:7888:47
    7888     (selector: Type<any> | Function | string, opts: {
                                                       ~~~~~~~
    7889         read?: any;
         ~~~~~~~~~~~~~~~~~~~
    7890         static: boolean;
         ~~~~~~~~~~~~~~~~~~~~~~~~
    7891     }): any;
         ~~~~~
    An argument for 'opts' was not provided.

Solution:

Find this line in your code at the location specified in the error message:

@ViewChild(MyOtherComponent) myOtherComponent: MyOtherComponent;

and add

{static: false}

as second argument to the @ViewChild() declaration:

@ViewChild(MyOtherComponent, {static: false}) myOtherComponent: MyOtherComponent;

In most cases, you want to use static: false. See this post on StackOverflow for details on when to use static: true as opposed to static: false.

Posted by Uli Köhler in Angular, Javascript, Typescript

How to remove all event listeners from a DOM element in Javascript

You can remove all event listeners from a DOM element in Javascript by replacing the element with a deep clone of itself. elem.cloneNode(...) will not clone the event listeners of the source element.

elem.replaceWith(elem.cloneNode(true));

Full example:

var elem = document.getElementById('mybutton');
elem.replaceWith(elem.cloneNode(true));

Source for the original (partial) suggestion on StackOverflow: @Felix Kling

Posted by Uli Köhler in Javascript