Javascript

How to configure Angular ‘ng serve’ API proxy

In order to proxy /api to http://localhost:62232 for example, first create proxy.conf.json in the same directory where package.json is located:

{
    "/api":
    {
        "target": "http://localhost:62232",
        "secure": false
    }
}

Now we need to modify package.json. Locate the line where ng serve is called, such as:

"start": "ng serve",

and add --proxy-config proxy.conf.json to the arguments of ng serve:

"start": "ng serve --proxy-config proxy.conf.json",

Full example for the scripts section of package.json:

"scripts": {
  "ng": "ng",
  "start": "ng serve ng serve --proxy-config proxy.conf.json",
  "build": "ng build --configuration=production",
  "watch": "ng build --watch --configuration development",
  "test": "ng test"
},

 

Posted by Uli Köhler in Angular, Javascript

How to get Jitsi meet list of participants using Tapermonkey script

Use this code in Javascript:

APP.conference.listMembers()

If no members are present, this will simply be an empty list:

> APP.conference.listMembers()
[]

But if there is another participant, it will show some info:

> APP.conference.listMembers()
[ci]
0: ci {_jid: '[email protected]/b009ae10', _id: 'b009ae10', _conference: nd, _displayName: 'Foo', _supportsDTMF: false, …}
length: 1

 

Posted by Uli Köhler in Audio/Video, Javascript

How to autojoin Jitsi Meet meeting using Tapermonkey script

This code clicks the join button:

document.querySelector(".prejoin-preview-dropdown-container div[role='button']").click()

By using the correct @match, you can activate this only for a specific conference:

Complete script:

// ==UserScript==
// @name         AutojoinJitsiMeet
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  ?
// @author       You
// @match        https://meet.jit.si/TestAutoJoin
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    document.querySelector(".prejoin-preview-dropdown-container div[role='button']").click()
})();

 

Posted by Uli Köhler in Audio/Video, Javascript

NodeJS typescript simple auto-reload on file change

First install ts-node-dev:

npm i --save-dev ts-node-dev

Then add

"start": "./node_modules/.bin/tsnd --respawn app.ts"

to package.json in the scripts section, example:

{
  "name": "myapp-backend",
  "version": "1.0.0",
  "description": "To make it easy for you to get started with GitLab, here's a list of recommended next steps.",
  "main": "index.js",
  "scripts": {
    "build": "./node_modules/.bin/tsc -b tsconfig.json",
    "start": "./node_modules/.bin/tsnd --respawn app.ts"
  }
  /* ... */
}

 

Posted by Uli Köhler in Javascript, NodeJS

How to get first day of next month in Javascript using DayJS

See the dayjs docs for more info about the library.

const now = dayjs();
const nextMonth = now.month(now.month() + 1).date(1).hour(0).minute(0).second(0);

// Example usage
console.info(nextMonth.format())
// Prints, for example, "2022-03-01T00:00:00+01:00"

This will also work in december as DayJS processes month(13) correctly:

const now = dayjs('2021-12-09');
const nextMonth = now.month(now.month() + 1).date(1).hour(0).minute(0).second(0);

// This prints '2022-01-01T00:00:00+01:00'
console.info(nextMonth.format());

 

Posted by Uli Köhler in Javascript

Angular: ActivatedRoute minimal example

For this route:

{path: 'my/:id', component: MyDashboardComponent},

this is how you can use it in MyDashboardComponent:

constructor(private route: ActivatedRoute) {
      this.route.params.subscribe(params => {
          console.info(params.id);
      })
}

 

Posted by Uli Köhler in Angular, Javascript

How to fix Angular Service ngOnInit() not being called

Problem:

You have an Angular service implementing OnInit:

import { Injectable, OnInit } from '@angular/core';

@Injectable()
export class MyService implements OnInit {

  constructor() { }
  
  ngOnInit() {
    console.log("MyService initializing");
  }
}

but it never prints MyService initializing – i.e. the ngOnInit() function is never actually being called.

Solution:

Services should not implement OnInit, the function is deliberately never called. Instead, add the code from ngOnInit() in the constructor() and remove implements OnInit and ngOnInit():

import { Injectable, OnInit } from '@angular/core';

@Injectable()
export class MyService {

  constructor() {
    console.log("MyService initializing");
  }
  
}

 

Posted by Uli Köhler in Angular, Typescript

How to fix Angular HttpClient toPromise() deprecated (rxjs)

Problem:

You have angular HTTP client code like

this.http.get<MyType>(`${this.baseURL}/api/myAPI`).toPromise()

but toPromise() is deprecated in recent versions of angular / rxjs.

/** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */
toPromise(): Promise<T | undefined>;

Solution:

In most cases, for HttpClient, you want to use rxjs’s firstValueFrom() since the HttpClient Observables typically only return one value anyway.

First, import firstValueFrom from rxjs:

import { firstValueFrom } from 'rxjs';

then remove the .toPromise() call:

// Before
this.http.get<MyType>(`${this.baseURL}/api/myAPI`).toPromise()
// After
this.http.get<MyType>(`${this.baseURL}/api/myAPI`)

and surround the entire statement with firstValueFrom:

// Before
this.http.get<MyType>(`${this.baseURL}/api/myAPI`)
// After
firstValueFrom(this.http.get<MyType>(`${this.baseURL}/api/myAPI`).toPromise())

This will fix the issue.

Posted by Uli Köhler in Angular, Typescript

Angular HTTPClient ReplaySubject example without query parameters

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { MyType } from './my-type';

@Injectable()
export class MyService {
  baseURL = "http://localhost:18674";

  // Replay subject: New subscribers will get previous values
  public nodes = new ReplaySubject<MyType>();

  constructor(private http: HttpClient) {
    // Currently only acquire nodes once
    this.http.get<MyType>(`${this.baseURL}/api/myapi`).subscribe(value => 
      this.values.next(value);
    });
  }
}

 

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

NodeJS MQTT minimal subscribe example with JSON messages

const mqtt = require('mqtt')
const client = mqtt.connect('mqtt://user:[email protected]')

client.on('connect', () => {
  client.subscribe('mytopic');
})

client.on('message', (topic, message) => {
  console.log(topic, JSON.parse(message))
})

If required, you can install the mqtt library using

npm i --save mqtt

 

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

How to compute SHA hash of local file in Javascript using SubtleCrypto API

The following example uses the SubtleCrypto API to compute the SHA-256 hash of a file that is selected in a file input. The checksum is computed entirely on the client side, the file does not need to be uploaded to a server at all.

This code has been verified to generate the same checksum as if running sha256sum on the command line.

Full example

You can download this file, save it as index.html and open it in the browser. Then select a file and check the develper

<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) {
                console.log("File", filename, ":");
                // 
                crypto.subtle.digest('SHA-256', ev.target.result).then(hashBuffer => {
                    // Convert hex to hash, see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string
                    const hashArray = Array.from(new Uint8Array(hashBuffer));
                    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string
                    console.log(hashHex);
                }).catch(ex => console.error(ex));
            };
            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 get page HTML source code in Puppeteer

In order to get the current page HTML source code (i.e. not the source code received from the server, but the currently loaded source code including Javascript modifications), use

await page.content()

Full example based on Puppeteer minimal example:

// Minimal puppeteer get page HTML source code example
const puppeteer = require('puppeteer');
(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://techoverflow.net', {waitUntil: 'domcontentloaded'});
  // Wait for 5 seconds
  console.log(await page.content());
  // Take screenshot
  await browser.close();
})();

 

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

How to sleep for X seconds in Puppeteer

In order to sleep for 5 seconds, use

await page.waitForTimeout(5000);

Full example based on Puppeteer minimal example:

// Minimal puppeteer example
const puppeteer = require('puppeteer');
(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://techoverflow.net', {waitUntil: 'domcontentloaded'});
  // Wait for 5 seconds
  await page.waitForTimeout(5000);
  // Take screenshot
  await page.screenshot({path: 'screenshot.png'});
  await browser.close();
})();

 

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

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:

sudo apt -y install curl
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/[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