The lazy-loaded module generates multiple instances of the parent service every time it is loaded

Whenever I switch from MainComponent to TestListComponent, the TestListComponent constructor gets called and a new instance of the ObservableService is instantiated. Clicking the link results in duplicated messages being displayed in the console. Could this be an Angular-related issue? Any suggestions?

main.module.ts

import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser'; 
    import {MainRoutingModule} from "./main-routing.module"; 
    import {MainComponent}   from './main.component';  
    import {ObservableService} from "../../core/services/observable.service";

    @NgModule({
        imports: [
            BrowserModule,
            MainRoutingModule,                   
        ],
        declarations: [MainComponent],
        providers: [ObservableService],
        bootstrap: [
            MainComponent
        ]
    })
    export class MainModule { }

main.routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

export const routes: Routes = [
    { path: 'tests', loadChildren: 'angular/app/modules/test-list/test-list.module#TestListModule'},
    { path: '**', redirectTo: '' }
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class MainRoutingModule {}

observable.service.ts

import { Injectable } from '@angular/core';
import {Subject} from "rxjs/Rx";
import 'rxjs/add/operator/map'


@Injectable()
export class ObservableService {

    // Observable string sources
    private changeLanguageStatus = new Subject<Object>();

    // Observable string streams
    changeLanguageStatus$ = this.changeLanguageStatus.asObservable();

    constructor(){}

    /**
     * Change language event
     * @param params
     */
    changeLanguageEvent(params: Object){
        this.changeLanguageStatus.next(params);
    }        
}

test-list.module.ts

import { NgModule } from '@angular/core';       
import {TestListComponent} from "./test-list.component";

@NgModule({
    declarations: [
        TestListComponent
    ]
})
export class TestListModule {}

test-list.component.ts

import {Component} from '@angular/core';
import 'rxjs/Rx';
import {ObservableService} from "../../core/services/observable.service";

@Component({
    moduleId: module.id,
    selector: 'st-test-list',
    templateUrl: 'test-list.component.html'
})

export class TestListComponent {

    constructor(private observableService:ObservableService) {
        observableService.changeLanguageStatus$.subscribe(
            data => {
                console.log('Test', data);
            });
    }    
}

main.component.ts

import {Component, ViewChild} from '@angular/core';
import 'rxjs/Rx';

import {ObservableService} from "../../core/services/observable.service"; 

@Component({
    moduleId: module.id,
    selector: 'st-main',
    templateUrl: 'main.component.html'       
})

export class MainComponent {      
   constructor(private observableService:ObservableService) {} 

   changeLanguage(lang){
      this.observableService.changeLanguageEvent({type: lang});
   }  
}

main.component.html

<a href="" (click)="changeLanguage('en')"></a>

<!--Dynamic content-->
<router-outlet></router-outlet>

Answer №1

It is important to note that when navigating to a component via routing, it should be created and when navigating back, it should be destroyed. Your issue may stem from creating an Infinite Observable where you continuously subscribe to a stream of events, in this case a change in language. Without unsubscribing from the Observable, the function subscribed to it remains active for each new instance of your component. Therefore, you must handle the disposal of your subscription yourself.

I recommend familiarizing yourself with Lifecycle hooks like OnInit and OnDestroy.

To properly manage your Observable subscriptions, use ngOnInit to subscribe and ngOnDestroy to unsubscribe as shown below:

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

@Component({ .... })

export class TestListComponent implements OnInit, OnDestroy
{ 
    private _languageSubscription : Subscription;

    ngOnInit(): void 
    {
        this._languageSubscription = observableService.changeLanguageStatus$.subscribe(
        data => {
            console.log('Test', data);
        }); 
    }

    ngOnDestroy() : void 
    {
        this._languageSubscription.unsubscribe();   
    }

}

By following these steps, you should be able to resolve your issue.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Transitioning React Hover Navbar Design

I'm currently revamping a click-to-open navbar into a hover bar for a new project. I have successfully implemented the onMouseEnter and onMouseLeave functions, allowing the navbar to open and close on mouse hover. However, I am facing an issue with ad ...

Using isClient in Gridsome: What You Need to Know

While working with the FirebaseUI and Gridsome plugin, I encountered an error message stating ReferenceError: window is not defined. This issue arises from server-side rendering (SSR) as FirebaseUI attempts to access the browser-specific window object. Af ...

Is there a way to access Instagram using Javascript for login?

Goal I am determined to automate the Instagram login process using Javascript by filling in the username and password fields, then clicking the log in button. My Attempts (with correct credentials): Access Instagram Login Page document.querySelector(&a ...

Choosing between a Blazor server application or Angular for integrating JWT functionality into your project

Greetings! I am currently working on a new web application that utilizes JWT authentication (token and refresh token). Initially, I opted to build the website using the Blazor framework due to my server side being developed with .NET Core. However, I hav ...

The primary origin of TypeScript is derived from the compiled JavaScript and its corresponding source map

Being new to sourcemaps and typescript, I am faced with a project that has been compiled into a single javascript file from multiple typescript files. The files available to me are: lib.js (the compiled js code of the project) lib.js.map (the source map ...

Is it possible to create a basic calculator with Vue.js by incorporating v-model and possibly v-if?

I am looking to create a Vue.Js component that includes an input field displaying the potential hours saved by a user switching to our software. How can I implement the v-if directive in this scenario? For users spending 20 - 30 hours, they would save 10 ...

Implementing validation for a Textbox based on changes in another component's value in React.js

Is it possible to trigger validation of a Textbox based on the value change of another custom component that updates the state? Handlers: handleValueChange = (val, elementName) => { this.setState({ ...this.state, [elementName]: val ...

pg-promise received an error due to an incorrect parameter being passed in for options

I have been working on transitioning my files from utilizing the pg package to the pg-promise package. Initially, everything was functioning correctly with the original pg solution I had in place. However, upon switching to pg-promise and referencing the d ...

Guidelines for retrieving a class name using jQuery when hovering over a div

I need assistance in fetching the class name by hovering over a div. Both divs have the same id but slightly different class names. Here is an example: <div id="1-someid" class="1-example-class border cz"> ...more elements go here.... </div> ...

Guide on automatically filling in another field depending on the choice made in a dropdown menu

I need assistance with fetching data from my database based on the selection of a drop-down list, which is populated from the same database. My current code seems to be causing me some trouble. Here's what I have so far: <head> <meta content ...

What is the correct way to integrate a HTML/CSS/JS theme into a Vue project effectively?

As a newcomer, I recently acquired a bootstrap theme that comes with HTML, CSS, and JavaScript files. My goal now is to integrate this theme into Vue in order to make it fully functional. The challenge I am facing is how to successfully incorporate the the ...

Creating a Date Computation Tool that Adds Additional Days to a Given Date

I have a challenge where Date 0 represents the start date, Date 1 is the result date after adding a certain number of days (NDays). I am looking for help in JavaScript to calculate Date0 + NDays = Date1. Please assist me as my coding knowledge is quite l ...

Create a new column in Material UI Grid by adding an empty div element instead of using padding

I'm currently getting acquainted with Material UI Grid and I am interested in adding an empty column (a blank space on the right of the first element) without utilizing padding. How can this be achieved? Here's a snippet of the code being discus ...

Troubleshooting Selenium JS: Challenges with Locating Elements Across Pages

I'm facing a challenge in accessing elements on pages other than the main page in my electron app. Although there are multiple elements that load when the app starts, I can only interact with elements on the initial page. I believe the issue lies in h ...

Using Jquery to add a list after parsing JSON data stored in localStorage

I've been stuck on this issue for quite some time now. The problem I'm facing involves checking the localStorage to see if there's a cached JSON string available. If there is, I load it and convert it back into a JSON object. If not, I make ...

The jQuery functions are unable to function properly when retrieving AJAX data

I am currently working on a script that inserts a record into my database using AJAX. After inserting the data, it is posted back in the following format... Print "<li>"; Print "<span class='cost'>" . $bill. "</span> "; Print ...

Effectively handle multiple connections from nodejs to postgres using the pg library

I need to run a script that performs multiple queries using the pg library for managing connections. However, I am facing an issue where my program stops working when the connection pool is full and does not queue future queries. I have tried setting the p ...

When trying to convert to JSON in node, the process fails. However, the data can still be

I am currently working on converting an array to JSON in order to send it to a client. The data I see in the console is as follows: [ NL: [ true, true, true, true, true, true, true, true, true, true, true, true ], ...

JavaScript for switching between grid layouts

I have organized 3 DIVs using a grid layout. There is a Navigation bar with an on-click event attached to it. When a button on the nav-bar is clicked, I want the JavaScript function to display the corresponding grid associated with that button. Currently, ...

Experiencing difficulty retrieving individual :id information from a list in MEAN stack

**I'm experiencing issues retrieving a single :id from a list as the data returned is not what I expected... ** GET /article/5b0be8829f734a4e580a43c5 401 3.845 ms - 99 ===> response from my get request my api ===> var express = require ...