Typescript

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

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 fix Angular ‘Cannot find control with unspecified name attribute’

Problem:

In your Angular2/4/5 application you see this error message:

Cannot find control with unspecified name attribute

Solution:

Look for a statement in the HTML angular template like this:

[formControl]="myCtrl"

The error message means that myCtrl can’t be found. Check if this variable is present in your class – it needs be a FormControl which you can import from @angular/forms:

import { FormControl } from '@angular/forms';

In my case, changing it to

[formControl]="myControl"

fixed the issue

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

How to fix Angular4/5/6 ‘No provider for ControlContainer’

Problem:

In your Angular2/4/5 application you’re getting the following error message:

No provider for ControlContainer ("<div class="recall-container mat-elevation-z8">

Solution:

You have not added the @angular/forms FormsModule to your module’s import list.

Go to your app.module.ts and add this line to the imports:

import { FormsModule } from '@angular/forms';

and look for a line like this in your module definition:

imports: [ /* several import modules may be listed here */ ],

and add FormsModule like this (if there are already imports, add FormsModule to the list):

imports: [ FormsModule ],
Posted by Uli Köhler in Angular, Javascript, Typescript

How to fix error TS2339: Property ‘userLanguage’ does not exist on type ‘Navigator’.

Problem:

When developing with typescript,  e.g. with Angular2, you get an error message similar to this one:

error TS2339: Property 'userLanguage' does not exist on type 'Navigator'.

Solution:

Check the error message for the correct file and line. Look for a statement like

window.navigator.userLanguage

Currently typescript does not have userLanguage as a property (tested with typescript up to 2.7.1), although it should already be fixed according to this issue.

You can work around this by simply replacing the statement listed above by

window.navigator['userLanguage']

Using this approach, Typescript will simply not check if the attribute is present or not.

Posted by Uli Köhler in Typescript