Multiple subscriptions to a Typescript service in an AngularJS controller have caused an issue with unsubscribing from it

Issue at Hand: I am currently working on merging AngularJS with Angular by creating components and services to be used within an AngularJS controller.

The AngularJS Controller is initiated through $routeProvider.

One of the components I have created is a card view, displaying a grid layout with images and buttons for approving/rejecting content. Clicking on these buttons opens an md-dialog pop-up to add messages and other details.

Within the TypeScript service, I have implemented functions to fetch and update data for the pop-up accordingly.

By clicking on the component button, the TypeScript service is called to set the data, and in the AngularJS controller, I have subscribed to the service's get function.

There are two main issues that I am encountering:

  1. Each time the page loads, the service gets subscribed. For instance, if I open the page three times, the service gets subscribed thrice, leading to the pop-up appearing multiple times when the component button is clicked.

  2. When attempting to unsubscribe from the service during loading and then subscribe again, the subscription does not happen, resulting in the pop-up not showing up.

Below is the code snippet for the TypeScript service:

import { BehaviorSubject, Observable } from 'rxjs';
import * as angular from 'angular';

class CardClickDTO {
    event;
    item;
    type: string;
}

let app = angular.module('PortalApp');
app.factory('contentcardSrv', [function (): {} {

    let cs = this;

    // Observables for Click Content
    cs._cardClickModel$ = new BehaviorSubject(new CardClickDTO());
    cs.CardClcikModel$ = cs._cardClickModel$.asObservable();

    // Get Data
    cs.getOnContentClickData = new Observable<CardClickDTO>(() => {
        return cs.CardClcikModel$;
    });

    // Set Data
    cs.setOnContentClick = (event, item, type: string): void => {
        let co: CardClickDTO = new CardClickDTO();
        if (type == "reset") // to reset Observable
            cs._cardClickModel$.next(co);
        else {
            co.event = event;
            co.item = item;
            co.type = type;
            cs._cardClickModel$.next(co);
        }
    };

    return {
        setOnContentClick: cs.setOnContentClick,
        getOnContentClickData: cs.getOnContentClickData,
    };
}]);

Now for the AngularJS Controller:

import { portal } from '../portal';
import { saveAs } from 'file-saver';

portal.controller('controller', ['$scope', '$http', '$window', '$mdDialog', '$location', '$cookies', '$mdSidenav', '$mdToast', '$timeout', '$mdpTimePicker', '$interpolate', 'Map', '$sce', '$filter', 'menuSv', 'contentcardSrv', 'permissionSrv', '$anchorScroll', 
    function ($scope, $http, $window, $mdDialog, $location, $cookies, $mdSidenav, $mdToast, $timeout, $mdpTimePicker, $interpolate, Map, $sce, $filter, menuSv, contentcardSrv, permissionSrv, $anchorScroll) {

 // Subscribed to the get data function of the service
 contentcardSrv.getOnContentClickData().subscribe((co) => {
            if (co != undefined && co.event != undefined && co.item != null && co.item != undefined && co.type != "" && co.type != undefined) {
                $scope.onContentClick(co.event, co.item, co.type);
                co.event.stopPropagation();
            }
        });

 $scope.onContentClick = function (ev, item, type) {
     // Show md-dialog pop-up.
     };
}]);

Lastly, the contentcard.component.ts file:

//import angular from 'angular';
import { portal } from 'js/portal';

portal.component('contentcardComponent', {
    templateUrl: './contentcard.component.html',
    controllerAs: 'ctrl',
    controller: 'contentcardComponentController',
    bindings: {
        itemsdata: '@',
        viewdata: '@'
    }
});

portal.controller('contentcardComponentController', ['contentcardSrv',
    function (contentcardSrv): void {

        const ctrl = this;

        // Component click function
        ctrl.onContentClick = function (ev, item, type: string): void {
            if (type == "Approved" || type == "Rejected" || type == "Partial" || type == "ApproveMessage")
                ctrl.btnClicked = true;
            contentcardSrv.setOnContentClick(ev, item, type); // Set data service function
        };
    }]);

Answer №1

Resolved the issue by utilizing the $destroy event in AngularJS.

Within the AngularJS Controller:

let clickSubscription = itemService.getClickData().subscribe((item) => {
        if (item != undefined && item.type != "") {
            $scope.onClick(item.type);
            item.stopPropagation();
        }
    });

$scope.$on('$destroy', function onDestroy() {
            // Clean up code when controller is destroyed
            // Release resources, cancel requests...
            clickSubscription.unsubscribe();
        })

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

Vue JS: Breathing Life into Your Elements

Incorporating Vue-Router and Vuex, I have successfully implemented a Users Profile Component that fetches user information by extracting the username parameter from a router-link. For example, <router-link :to="{name: 'user', params: { usernam ...

Steps for resolving the problem of the Express error handler not being executed

This question has come up again, and I have searched for solutions but none seem to work. Your assistance in debugging the issue would be greatly appreciated. I have a separate errorHandler set up as middleware. In my error-handler.ts file: import expres ...

Exploring the concept of String Enums through Reverse-Mapping

I was exploring the use of string enums in TypeScript and came across an issue with reversed mapping support. Here's what my enum looks like: enum Mode { Silent = "Silent", Normal = "Normal", Deleted = "Deleted" } I want to be able to pa ...

Tips for preserving scroll location on Angular components (not the window) when navigating

My current layout setup is like this: https://i.sstatic.net/hOTbe.png In essence <navbar/> <router-outlet/> The issue I'm facing is that the router-outlet has overflow: scroll, making it scrollable (just the outlet section, not the ent ...

Difficulty encountered while trying to link an abstract class with Redux state using redux-thunk

My approach to using redux-thunk and class components in React follows a basic pattern. The code below shows how a class definition MyClass is exported, correctly connected to state through mapStateToProps, and has access to actions from mapDispatchToProps ...

In JavaScript, the function yields a proxy rather than an object

Let's say I have an array: const arr = ['one', 'two', 'three'] Now, imagine I have a function that is designed to take an array of strings and return an array of objects: const func = (arr) => arr.map(item => ({str ...

Retrieving POST request headers in Nightmare JS following a click() function execution and a wait() function delay

When I navigate a page, I input something in a field using type(), click on a button with click(), and then wait for an element to appear using wait(). I am interested in retrieving all the headers associated with the POST request that is triggered after ...

Loop through the array of objects using ng-repeat and generate input forms

[{"id":1,"inputfieldbox":[{"id":1},{"id":2}]},{"id":2,"inputfieldbox":{"id":1}}] I plan to implement NG-repeat for form iteration. The inputfield box represents the amount of input boxes I will include, while id indicates the number of field groups requi ...

Can you suggest an alternative for the "return" statement within a "for loop" in order to retrieve all values from the loop?

When using numInOrder + " : " + nameInOrder;, the console only displays one value: "1 : a". However, I would like to see: "1 : a 2 : b 3 : c 4 : d 5 : e 6 : f" in the console.log output. Additionally, I do not want to use consol.log(numInOrder + " ...

Maintaining the position of the input cursor when using the arrow up and down keys in AngularJS directive

I am currently developing a custom "typeahead/autocomplete" directive. element.bind("keydown keypress", function (event) { if(event.which === 38 || event.which === 40) { var increment = event.which === 38 ? 1: -1; ... .. ...

Interactive hover image that reveals hidden information when clicked

I am trying to implement 3 rollover images as triggers to display text boxes underneath each image. However, when I click on the image, it disappears and does not function properly. I am currently focusing on getting the first one to work. To view my code ...

Tips for CSS: Preventing onhover animation from resetting with each hover

I've created an on-hover CSS animation that smoothly transitions between images. However, I encountered a lagging issue when the user quickly hovers over SECTION ONE and SECTION TWO before the animation ends, causing the animation to restart and lag. ...

Are the files selected by the user not displaying properly in the URL?

I'm currently working on a project using PhoneGap where I am facing an issue with uploading files and adding all file names to the parameters. The desired format is: http://www.example.com/uplaod.html?file=file1,file2,file3 To achieve this, I have a ...

Expanding the size of a div using the Bootstrap grid system

I need to customize the width of the date column on my inbox page so that it displays inline without breaking the word. Even when I use white-space: nowrap, the overflow hides it due to the fixed width. I want the name and date classes to be displayed in ...

Create a collection of boxes using THREE.js and save them in a 3D array

My latest project involves rendering a 16x16 grid of boxes in THREE.js using custom code. const drawGroup = () => { const blockSize = 16 // Positioning for (let x = 0; x < blockSize; x++) { for (let y = 0; y < blockSize; y++) ...

What is the method for retrieving a temporary collection in a callback function when using node-mongodb-native find()?

Is it possible to retrieve a temporary collection from a find() operation instead of just a cursor in node-mongodb-native? I need to perform a mapReduce function on the results of the find() query, like this: client.open(function(err) { client.collect ...

Animation not properly synced with Bootstrap 4 Dropdown hide event

Could you please check out my codepen for clarification: http://codepen.io/anon/pen/oLZOyp Essentially, I have integrated two animations using animate.css into Bootstrap 4 show.bs.dropdown and hide.bs.dropdown events. The animations work on the first show. ...

Analyzing exif data during the process of uploading a batch of images

My website allows users to upload multiple images simultaneously. I want to check the EXIF rotation tag of each uploaded image in order to manually rotate the images in the browser if needed. I came across a solution for reading the EXIF rotation value of ...

Integrating webpack with kafka-node for seamless communication between front

I am in the process of embedding a JavaScript code that I wrote into an HTML file. The script requires kafka-node to function properly, similar to the example provided on this link. To achieve this, I am using webpack to bundle everything together. I am fo ...

Merge arrays to form nested structures

Here's a mind-bending scenario for you. Imagine I have two arrays - one containing categories and the other containing arrays that follow the structure of those categories. For example: var categoryArray = ["Name", "Title", "Hire Date"]; var infoArr ...