The continuity of service value across parent and child components is not guaranteed

My goal is to update a value in a service from one component and retrieve it in another.

The structure of my components is as follows: parent => child => grandchild

When I modify the service value in the first child component, the parent receives the correct value from the service. However, if I update the value in a more nested child component, the parent does not get the accurate value.

Here is the code snippet:

service.ts

@Injectable()
        export class ConfirmationDialogService {
            componentHasDirtyForm: boolean; // value to set
            constructor(private confirmationDialogReferenceService: ConfirmationDialogReferenceService,
                        private dialog: MatDialog) { }
        

parentComponent.ts

constructor(private confirmService: ConfirmationDialogService) {
    }

    ngOnInit() {
    }

    isDirty(): boolean {
        console.log(this.confirmService.componentHasDirtyForm)
        return this.confirmService.componentHasDirtyForm;
    }
    

ChildComponent.ts

constructor(private confirmService: ConfirmationDialogService) { }

    ngAfterViewChecked(){
        this.confirmService.componentHasDirtyForm = this.generalInfoForm.dirty;
    }
    

GrandchildComponent (rendered inside child component)

constructor(private confirmationService: ConfirmationDialogService) { }
        ngAfterViewChecked(){
            this.checkForDirtyForm();
        }

        checkForDirtyForm(){
            for(var i = 0; i < this.ContactFormArr.length; i++){
                if(this.ContactFormArr.at(i).dirty){
                    this.confirmationService.componentHasDirtyForm = true;
                    break;
                }
            }
        }
    

In essence, in the grandchild component, I am attempting to update the `componentHasDirtyForm` property of the `ConfirmationDialogService`. It works correctly in the parent if updated from the child, but not from the grandchild.

I have also added the service as a provider in app.module.ts

Answer №1

When you define your service like this:

@Injectable(
{
  provide:root
})

(as a Wand Maker commented), the service becomes shared across the entire application.

However, if you declare the service using providers:[] in the main module (making it common to all components) or in a module that contains all the components, then the service will also be shared.

On the other hand, if you specify the service as a provider for each component or inject it using Injector, then the service will be unique for each individual component.

Answer №2

Implementing componentHasDirtyForm as an observable within a service allows you to connect it with multiple components such as parent, child, and grandchild, ensuring they all have access to the same value consistently.

// Custom Service
private readonly _componentHasDirtyForm = new BehaviorSubject<any>({});
public readonly $componentHasDirtyForm = this._data.asObservable();

// Component
public componentHasDirtyForm: Observable<any>;

ngAfterViewChecked() {
   this.componentHasDirtyForm = confirmationService.$componentHasDirtyForm;
}    

// Template
<div>{{ componentHasDirtyForm | async }}</div>

Answer №3

After some troubleshooting, I was able to identify the root cause of the problem. It turns out that the Grandchildren/Children components were correctly setting the value of the service, but the issue lied in the Parent/Child component's ngAfterViewChecked() hook running after the hooks in the Grandchildren/Children.

This sequence was resulting in the service's value always reflecting the status of the Parent component (the higher level component). To resolve this, I implemented a workaround by updating the parent component's dirty check to conditionally modify the service based on its current value.

Here is an example of how I addressed the issue:

isDirty(): boolean {
    if(!this.confirmService.componentHasDirtyForm)
        this.confirmService.componentHasDirtyForm = formStatus;
}

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

Managing CORS in Angular2 for REST WebApi calls

Currently, I am utilizing an Angular 2 front end along with a WebApi backend where the WebApi is CORS enabled. var cors = new EnableCorsAttribute("*", "*", "*"); GlobalConfiguration.Configuration.EnableCors(cors); This setup works well with different sit ...

Issue with form using "target=_blank" to open PDF in web application home screen not functioning properly

I am encountering an issue in my Angular application where a form with target="_blank" successfully returns a PDF upon submission, but when accessed from the homescreen icon of the web-app in Android/Chrome, the new window opens blank without displaying th ...

How to retrieve Angular directive name using TypeScript

I have successfully implemented the following AngularJS directive: export module Directives { export class PasswordsMatch implements ng.IDirective { public static Factory(name: string) : ng.IDirectiveFactory { return () => new ...

The property 'owlDateTimeTrigger' cannot be bound to 'span' as it is not recognized

I have integrated the OwlDateTimeModule into my smart-table-datepicker component. Although I imported it in my smart-table-datepicker.module file, I am still encountering errors. What could be causing this issue? smart-table-datepicker.module.ts import { ...

Troubleshooting Problems with Linking Components to app.component.html in Angular

I have created a few components, but I am having trouble getting them to work properly. When running 'ng serve', I encounter errors. If 'app-test' is supposed to be an Angular component, make sure it is included in the '@Compone ...

Using Long Polling with Angular 4

I am looking for a way to monitor the progress of a certain task using API calls. To achieve this, I have developed a service that executes these API calls every 1.5 seconds Main Component private getProgress() { this.progressService.getExportPr ...

How can we exclude fields from JSON.stringify in type-graphql entities?

Utilizing https://github.com/MichalLytek/type-graphql for crafting our graphql schema has posed a challenge. When we serialize the TypeScript entity object, it does not adhere to the field annotations in our GQL entities, resulting in unwanted data leakage ...

Exploring methods in Firebase Cloud Functions to retrieve and modify values

I'm currently attempting to retrieve a value from a specific location in my database, add 1 to it, and then update it back. However, I keep encountering various errors, with the most recent being: TypeError: Cannot read property 'update' of ...

The plugin needed for the 'autoprefixer' task could not be located

Starting out in the world of Angular 2 development can be overwhelming, especially when trying to integrate with the Play framework on the back-end side. I recently came across a helpful post by Denis Sinyakov that walks through setting up this integratio ...

Encountering an Angular 13 ChunkLoadError during application deployment, despite the presence of the respective chunk

We encountered an issue with our application's upgrade from Angular 11 to 13. While running 'ng serve' on the local machine works fine, deploying it to our Azure app service causes the lazy loaded modules to fail loading. The specific error ...

Even when imperfections inevitably arise, flawless submission is always achieved

When working with a form that has a set minimum and maximum number of characters, I encounter an issue. If the minimum is set to 2 characters and I only input one character, I receive a mat-error message. However, upon clicking save, it allows me to procee ...

Exclude the header HTML when exporting data to a file with jQuery DataTables

I've encountered a problem with my simple data table. I added a custom tool-tip div in the datatable for the headings, following this reference. However, when I export the file to excel or PDF, the tooltip text is also included in the exported file. ...

Exploring the Various Path Options in Angular 2 Routing

As a newcomer to Angular and Node JS, I am currently working on an application and struggling with how to efficiently navigate between my different components. Users can input the name of a user and add books associated with them When clicking on a book ...

Utilizing MUI for layering components vertically: A step-by-step guide

I am looking for a way to style a div differently on Desktop and Mobile devices: ------------------------------------------------------------------ | (icon) | (content) |(button here)| ----------------------------------------- ...

Ways to ensure ngModel is accessible across components

I've hit a wall and I'm starting to lose my mind. I've tried all the different methods like FormsModules, ReactiveForms, FORMDIRECTIVES, Input, Output, but I just can't seem to figure out how to make ngModel work between components. My ...

In my attempt to assess the correlation between value 1 and a value in the preceding object, I am utilizing the *ngFor directive

Attempting to compare 2 entries in an *ngFor loop. The code should compare the value at the current object to a value at the previous object. <ng-container *ngFor="let item of s_1.comments[0]; index as b"> <article class="message i ...

Tips for sending data through BLE with Ionic 3 and Angular 4

Here is my first question. I am currently utilizing the cordova-plugin-ble-central plugin to transfer data through my BLE device. I am struggling to grasp the process of sending data. My objective is to transmit a group of 8 bytes using a Unit8Array. Th ...

Tips for customizing a generic repository error message

I have a GenericRepository class that provides basic functionality for interacting with persistence storage such as creating, finding, getting all, deleting, and updating data. Within the find method, I am searching the database using its primary key. If ...

Is there an easier method to utilize ES6's property shorthand when passing an object in TypeScript, without needing to prefix arguments with interface names?

When working with JavaScript, I often find myself writing functions like the one below to utilize ES6's property shorthand feature: function exampleFunction({param1, param2}) { console.log(param1 + " " + param2); } //Usage: const param1 = "param1" ...

Eliminating the most recent entry from the dropdown menu

Currently, I am exploring angular drag and drop functionality in my project. Here is the code snippet that I am using: Link to Code In the implementation, whenever an item is dropped, it automatically goes to the end of the "done" list. What I am looking ...