Javascript

Angular: How to inject child component class by ID via ViewChild

<app-my-component #myId></app-dynamic-plot>
@ViewChild('myid', {read: MyComponent}) myComponent!: MyComponent;

 

Posted by Uli Köhler in Angular

How to hide password strength meter with PrimeNG [p-password] InputPassword

Use [feedback]="false" to hide the strength meter:

<p-password [feedback]="false" [(ngModel)]="value"></p-password>

 

Posted by Uli Köhler in Angular

How I fixed Angular “ng build”, “ng new” etc not terminating

Problem

On my Desktop, Angular commands such as

ng build

or

ng new

worked successfully, but they didnt stop / terminate after running the command. Instead, they just waited indefinitely without any output.

Solution:

This is related to analytics being enabled, see this GitHub post.

In order to fix it, run

ng analytics disable --global

It will print

Global setting: disabled
Local setting: enabled
Effective status: disabled

and it won’t terminate the first time you do this. Just press Ctrl+C to force stop it.

After that, any command will exit after finishing its task

Underlying problem

I suspect this has something to do with IPv6 configuration since my Desktop’s IPv6 network setup is somewhat broken at the moment. However, I did not do any further research into this.

Posted by Uli Köhler in Angular

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

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

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg

NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list

sudo apt-get update
sudo apt-get install nodejs -y

 

Instead of 20 you can also choose other versions like 18. 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 fix Angular standalone component: Can’t bind to ‘routerLink’ since it isn’t a known property of ‘a’

Problem:

When opening your Angular app with a standalone component, you see the following error message:

Can't bind to 'routerLink' since it isn't a known property of 'a'

Solution:

In the component where the error occurs, add

import { RouterModule } from '@angular/router';

and add

RouterModule,

to the imports of the component. Example:

@Component({
  selector: 'app-top-bar',
  standalone: true,
  imports: [
    CommonModule,
    RouterModule
  ],
  templateUrl: './top-bar.component.html',
  styleUrl: './top-bar.component.sass'
})
export class TopBarComponent {

}

 

Posted by Uli Köhler in Angular, Typescript

How to make header row bold using xlsx / SheetJS

Based on our previous example How to make cell bold using xlsx / SheetJS, the following code example will set {s: {font: {bold: true}} for every cell of the first row.

This code assumes that you know the number of columns (header.length in this example).

Add the following code after adding the cell content to the worksheet.

// Make first row bold
for(let i = 0; i < headers.length; i++) {
    const cell = ws[XLSX.utils.encode_cell({r: 0, c: i})];
    // Create new style if cell doesnt have a style yet
    if(!cell.s) {cell.s = {};}
    if(!cell.s.font) {cell.s.font = {};}
    // Set bold
    cell.s.font.bold = true;
}

 

Posted by Uli Köhler in Javascript, Typescript

How to make cell bold using xlsx / SheetJS

First, you need to understand that stock xlsx / SheetJS community edition does not support cell styling as of August 2023.

Hence, you need to use the fork xlsx-js-style which you can install using

npm i --save xlsx-js-style

Now, based on our previous example, use these imports

import * as XLSX from 'xlsx-js-style';
import { saveAs } from 'file-saver';

and this code to generate a XLSX file with a bold cell:

// Create an empty workbook
const wb = XLSX.utils.book_new();

// Create an empty worksheet
// If this weren't a minimal example, your data would go here
const ws = XLSX.utils.aoa_to_sheet([
    ["Test"]
]);

// Make cell bold
ws["A1"].s = {
    font: {
        bold: true,
    }
};

// Add the worksheet to the workbook
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');

// Export the workbook to XLSX format
const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'buffer' });

// Convert the binary data to a Blob
const blob = new Blob([wbout], { type: 'application/vnd.ms-excel' });

// Download of the file using file-saver
saveAs(blob, 'example.xlsx');

 

Posted by Uli Köhler in Javascript, Typescript

Which tsc –target to use for different NodeJS versions?

Depending on the minimum NodeJS version you intend to support,, you should use the following –target settings for tsc:

  • Node 10.x: es2018
  • Node 12.x: es2019
  • Node 14.x: es2020
  • Node 16.x: es2021
  • Node 17.x: es2022
  • Node 18.x: es2022
  • Node 19.x: es2022
  • Node 20.x: es2022

Note that there are more configurations possible than just --target when compiling for NodeJS. See the tsconfig base config examples on Github for more details.

Source: The tsconfig bases on Github.

Posted by Uli Köhler in NodeJS, Typescript

NodeJS TCP ping example (Typescript)

The following Typescript example allows you to “ping” an IP address or host name not using ICMP but using TCP connection to a given port. If the TCP connection is accepted, the ping is resolved as true. If no connection can be established, it is returned as false. In any case, no data is exchanged and the connection is closed immediately after establishing it.

import { Socket } from "net";

/**
 * Basic TCP ping that returns true if the connection is successful, false if it fails
 * The socket is closed after the connection attempt, no data is exchanged.
 */
export function TCPConnectPing(ipAddress, timeout=5000, port=80): Promise<boolean> {
    return new Promise((resolve) => {
      const socket = new Socket();
      let connected = false;
  
      // Set a timeout for the connection attempt
      const timer = setTimeout(() => {
        if (!connected) {
          socket.destroy();
          resolve(false); // Connection timed out
        }
      }, timeout);
  
      socket.connect(port, ipAddress, () => {
        clearTimeout(timer);
        connected = true;
        socket.destroy();
        resolve(true); // Connection successful
      });
  
      socket.on('error', (error) => {
        clearTimeout(timer);
        if (!connected) {
          resolve(false); // Connection failed due to error
        }
      });
    });
  }

 

Posted by Uli Köhler in Networking, NodeJS

How to fix NodeJS / NPM “TypeError: Class extends value undefined is not a constructor or null” in /usr/lib/node_modules/npm/node_modules

Problem:

When you try to run any npm command such as npm start , you see an error message such as

/usr/lib/node_modules/npm/lib/es6/validate-engines.js:31
    throw err
    ^

TypeError: Class extends value undefined is not a constructor or null
    at Object.<anonymous> (/usr/lib/node_modules/npm/node_modules/fs-minipass/lib/index.js:136:4)
    at Module._compile (node:internal/modules/cjs/loader:1233:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1287:10)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Module._load (node:internal/modules/cjs/loader:938:12)
    at Module.require (node:internal/modules/cjs/loader:1115:19)
    at require (node:internal/modules/helpers:119:18)
    at Object.<anonymous> (/usr/lib/node_modules/npm/node_modules/cacache/lib/content/read.js:4:13)
    at Module._compile (node:internal/modules/cjs/loader:1233:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1287:10)

Solution:

This is an internal error in npm or packages required by npm. Typically, it is caused by an incomplete update of NodeJS and npm which leaves npm or its dependencies in a broken state.

The solution is to reinstall NodeJS:

  • Uninstall NodeJS using a command such as
    sudo apt remove nodejs
  • Remove the NodeJS package folder entirely, on Linux it can be moved to a backup location using e.g.
    sudo mv /usr/lib/node_modules ~/node_modules_backup
  • Re-installing NodeJS using a command such as
    sudo apt -y install nodejs
  • Re-installing any globally installed packages you need, such as npm i -g @angular/cli
Posted by Uli Köhler in NodeJS

Do Docker “node” images have ssh-keygen?

I tested with node:20 and node:20-alpine and can confirm that:

  • node:20 (i.e. debian bookworm based) has a working ssh-keygen
  • node:20-alpine does not have ssh-keygen

On Alpine, you can install ssh-keygen using apk.

Typically, this means you have to build your own docker image based no node:20-alpine. In your Dockerfile, add

RUN   apk update && \
      apk add --no-cache \
      openssh-keygen

 

Posted by Uli Köhler in Docker, NodeJS

How to fix Angular error TS2552: Cannot find name ‘Input’. Did you mean ‘oninput’?

Problem:

You see the following error message while compiling your angular application:

Error: src/app/my/my.component.ts:9:4 - error TS2552: Cannot find name 'Input'. Did you mean 'oninput'?

Solution:

Open your module file, e.g. my.component.ts and add the following line at the top:

import { Input } from '@angular/core';

 

Posted by Uli Köhler in Angular, Typescript

How to fix Angular Can’t bind to ‘routerLink’ since it isn’t a known property of

If you see an error message such as

Error: src/app/my-component/my-component.component.html:2:1 - error NG8002: Can't bind to 'routerLink' since it isn't a known property of 'p-button'.
1. If 'p-button' is an Angular component and it has 'routerLink' input, then verify that it is part of this module.
2. If 'p-button' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.

in your angular app, open the module file that is declaring your component (typically app.module.ts) and add

RouterModule,

to its imports, for example:

imports: [
  CommonModule,
  RouterModule,
]
Posted by Uli Köhler in Angular

NodeJS MikroTik PoE status query example

This example builds on our previous posts NodeJS Mikrotik API minimal example and MikroTik RouterOS: How to power-cycle PoE using the terminal.

The following code will print the PoE status on Port ether5 on the given MikroTik device using the MikroTik API.

import * as MikroNode from 'mikrotik' ;

const host = "192.168.88.1";
const username = "admin";
const password = "admin1234"; // Hope that's not your real password ;)

const connection = MikroNode.getConnection(host, username, password, {
    closeOnDone : true
});

connection.getConnectPromise().then(function(conn) {
    conn.getCommandPromise(['/interface/ethernet/poe/print', '?name=ether5']).then(values => {
        console.log(values);
    }, reason => {
        console.log('Error while running command: ' + JSON.stringify(reason));
    });
}).catch(reason =>  {
    console.log('Error while connecting: ' + JSON.stringify(reason));
});

Example output:

[
  {
    '.id': '*5',
    name: 'ether5',
    'poe-out': 'forced-on',
    'poe-priority': '10',
    'poe-lldp-enabled': 'false',
    'power-cycle-ping-enabled': 'false',
    'power-cycle-interval': 'none',
    '.about': 'poe-out status: power_reset'
  }
]

If the PoE is currently being power-cycled, this will print:

[
  {
    '.id': '*5',
    name: 'ether5',
    'poe-out': 'forced-on',
    'poe-priority': '10',
    'poe-lldp-enabled': 'false',
    'power-cycle-ping-enabled': 'false',
    'power-cycle-interval': 'none',
    '.about': 'poe-out status: power_reset'
  }
]

 

Posted by Uli Köhler in MikroTik, NodeJS, PoE

NodeJS Mikrotik API minimal example

This is an example of access the Mikrotik API using NodeJS and the mikrotik package.

First, install the package

npm i --save mikrotik

Also, in order to enable import statement, set

"type": "module"

in package.json.

Example code:

import * as MikroNode from 'mikrotik' ;

const host = "10.56.23.4";
const username = "admin";
const password = "N@CdVTz8y@D$KwVS5TTo"; // Hope that's not your real password ;)

const  connection = MikroNode.getConnection(host, username, password, {
    closeOnDone : true
});

connection.getConnectPromise().then(function(conn) {
    conn.getCommandPromise('/ip/address/print').then(addresses => {
        for(const address of addresses) {
            console.info(`Address: ${address.address} on ${address.interface}`);
        }
    }, reason => {
        console.log('Error while running command: ' + JSON.stringify(reason));
    });
}).catch(reason =>  {
    console.log('Error while connecting: ' + JSON.stringify(reason));
});

This will output, for example:

Address: 192.168.88.1/24 on bridge
Address: 10.1.2.3/24 on bridge

In case of bad username/password credentials, it will print:

Error while connecting: {"errors":[{"category":"","message":"invalid user name or password (6)"}],"channelId":"login","channel":{"id":"login","running":true,"closing":true,"closed":true,"clearEvents":false,"saveBuffer":true,"closeOnDone":false,"lastCommand":["/login","=name=admin","=password=admin1234",".tag=login"],"_events":{},"_eventsCount":0}}

 

Posted by Uli Köhler in MikroTik, NodeJS

How to generate SSH public & private key in NodeJS using ssh2 library

The following code is a Promise based wrapper around ssh2’s utils.generateKeyPair():

const { utils: { generateKeyPair } } = require('ssh2');
const {writeFile} = require('fs/promises');

/**
 * ssh2's generateKeyPair as promise
 */
function SSHGenerateKeyPairPromise(keytype="ed25519", opts = {}) {
    return new Promise((resolve, reject) => {
        generateKeyPair(
            keytype, opts,
            (err, keys) => {
                if (err) { return reject(err) };
                return resolve(keys);
            }
        );
    });
}

/**
 * Run SSHGenerateKeyPairPromise() and save the keys to
 * opts.privateKeyPath and opts.publicKeyPath
 * @returns The generated keys
 */
async function SSHGenerateAndSaveKeyPairPromise(keytype="ed25519", opts = {}) {
    // Check if opts.privateKeyPath and opts.publicKeyPath are set
    if (!opts.privateKeyPath || !opts.publicKeyPath) {
        throw new Error("opts.privateKeyPath and opts.publicKeyPath must be set");
    }
    const keys = await SSHGenerateKeyPairPromise(keytype, opts);
    //Save keys to opts.privateKeyPath and opts.publicKeyPath using fs.promise
    await writeFile(opts.privateKeyPath, keys.private);
    await writeFile(opts.publicKeyPath, keys.public);
    return keys;
}

Usage example for ed25519 keys:

SSHGenerateAndSaveKeyPairPromise('ed25519', {
    privateKeyPath: 'id_ed25519',
    publicKeyPath: 'id_ed25519.pub'
}).then(keys => {
    console.log("Successfully generated ed25519 keys");
}).catch(err => {
    console.log(err);
});

Usage example for rsa keys:

SSHGenerateAndSaveKeyPairPromise('rsa', {
    bits: 8192,
    privateKeyPath: 'id_rsa',
    publicKeyPath: 'id_rsa.pub'
}).then(keys => {
    console.log("Successfully generated RSA keys");
}).catch(err => {
    console.log(err);
});

 

Posted by Uli Köhler in NodeJS

How to fix NodeJS argon2 crash

My NodeJS app using the argon2 library crashed within my docker container (the process just exited without an error message) every time I used argon2 funtions, even though it worked fine on my Desktop.

This error occured with argon2==0.30.3I fixed it by downgrading it to 0.26.2 using the following statement in package.json:

"argon2": "^0.26.2",

With the correct version installed (don’t forget to npm install after changing package.json), the issue disappeared entirely. I did not try any other versions of argon2.

Posted by Uli Köhler in NodeJS

What is the NodeJS equivalent of Python’s if name == “__main__”

Whereas in Python you would use

if name == "__main__":
    # TODO Your code goes here

in NodeJS you can simply use

if (require.main === module) {
    // TODO Your code goes here
}

 

Posted by Uli Köhler in Javascript, NodeJS

How to set Koa HTTP response code

In order to set the HTTP response code using Koa, use ctx.status = ...

ctx.status = 403;

Full example:

const Koa = require("koa");

const app = new Koa();

app.use(async (ctx, next) => {
  ctx.status = 403;
  ctx.body = "Forbidden";
});

app.listen(3000);

 

Posted by Uli Köhler in Javascript, NodeJS