How to make components in Angular 2 singleton?
Asked Answered
I

4

10

I am using Angular 2 to build my web application which which has lot of components. I am using angular-cli to create, run and build the project.
Accidentally (or luckily) I stumbled across a bug where I realized that multiple instances of my component were being created. Even worse was when I realized that my code was referring to any one this instances randomly without any logic to trace it back.

As an example, check the following scenario:

  • I logged into my application and made a REST call (on window resize event) in a specific component
  • An important point here is every user has an unique ID which is used in REST calls
  • Then I logged out from this user and logged in with another user
  • I went back to same component and made the same rest calls (again on window resize events), however to my shock, some of the rest calls were being made using the unique ID or earlier logged in user
  • To check my suspicion, I created a first class variable in the constructor which basically stores the value of Date.now(). This is turn would tell me when the class was instantiated.
  • Then I added a few console.log() statements which would show me which instance was being called by the value of my variable.
  • The log confirmed my suspicion that multiple instances indeed exist simultaneously and there is no certain logic or path followed to access anyone of them. This is the image of my log statement. I have blackened out the sensitive parts.

This is the image of my log statement. I have blackened out the sensitive parts. It can be clearly seen that some rest calls are being made with the unique id for tenant 1 while some for trial tenant. Also use of two instances is also very clear from two instance times. The old instance of previous logged in tenant is somehow still in play and my component is still able to access it.

My Questions are:

  1. Is there a way to make the component class singleton?
  2. Is there any way to destroy the component instance on leaving the component?
Isleana answered 31/1, 2017 at 10:2 Comment(2)
Unique id is important, why not to change the scope strategy to prototype.Battalion
@RomanC can you kindly elaborate a bit? Perhaps with an example or link?Isleana
C
3

I had the same problem when I add to define a tab which every time I choose one of the tab, it creates the component instead of using the last created one. My solution works for a simple components, and I am not sure that this solution is the right one but it worked for me as I said in a simple components.

Here is the code of the component which I want to have only one - like singleton

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

@Component({
  selector: 'app-main1',
  templateUrl: './main1.component.html',
  styleUrls: ['./main1.component.scss']
})
export class Main1Component implements OnInit, OnDestroy {

  static lastComp: Main1Component;

  constructor() {
    if (Main1Component.lastComp) {
      return Main1Component.lastComp;
    }
   }


  name: string;
  ngOnInit(): void {
    if (!Main1Component.lastComp) {
      this.name = 'Zion';
    }
  }

  ngOnDestroy(): void {
    Main1Component.lastComp = this;
  }
}

I am keeping the last created component in a static member and in the constructor if the static exist I use it instead of creating one. I am doing OnInit only once! In Destroy I keep the last one in the static member.

I hope it will help someone, will be glad to get any remark on this.

Coenurus answered 10/8, 2020 at 12:26 Comment(1)
+1. Got the Idea that static instance can work for such scenario. Btw, I assume, in given solution static member should not be part of same component, since on destroy of component static member will also get destroy, but can keep static instance somewhere outside component.Chrissa
G
2
  1. Is there a way to make the component class singleton?

not that i am aware of

  1. Is there any way to destroy the component instance on leaving the component?

yes, there is an interface OnDestroy

export class ClockComponent implements OnDestroy {
interval;

ngOnDestroy() {
  clearInterval(this.interval);
}

constructor() {
  this.interval = setInterval( ()=> console.log('tick') );
}
Gustavo answered 2/10, 2017 at 12:42 Comment(3)
There's a good doc about singleton services (Angular 6) here: angular.io/guide/singleton-servicesSlusher
Another option is to register the component only once in your main module, and it will act as a singleton: @NgModule({ providers: [ MY_COMPONENT ]})Slusher
Sounds like bad practice, any singleton thing in angular should be a serviceGustavo
R
0

Well I can identify with the need to have a component as a singleton because a service cannot have html, and you sometimes need to associate the html to be part of the singleton instance. But YOU CAN in-fact make a component a singleton:

private static _counter = 0;
static CountInstances() : Boolean {
  ++SingletonComponent._counter;
  if(SingletonComponent._counter > 1){
    return false;
  }
  return true;
}

if(!SingletonComponent.CountInsances()) //throw error and stop app from running
Romero answered 6/11, 2019 at 16:52 Comment(2)
not really helpful if you don't specify where this code should be implemented and how.Mauriciomaurie
A static class/function is not the same as a singleton. It may however be adequate for some cases.Weanling
G
0

Zion Bokobza's answer helped me but that Main1Component.lastComp = this; ought to be in the onInit not in the onDestroy, or else lastComp will remain null until the component is destroyed:

      ngOnInit(): void {
        if (!Main1Component.lastComp) {
          this.name = 'Zion';
          Main1Component.lastComp = this;
        }
      }
Gq answered 15/3 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.