Struggling to retrieve the value of a variable from a service in Angular

In my application, I've implemented a cookie checking service to monitor the status of my cookie consent popup:

@Injectable()
export class CookieCheckService implements OnInit, OnDestroy {
  public hasConsented = false;
  private cookieStatusChangeSubscription: Subscription;

  constructor(
    private ccService: NgcCookieConsentService
  ) {
  }

  ngOnInit() {
    if (this.ccService.hasConsented()) {
      this.hasConsented = true;
    }

    console.log(this.hasConsented);

    this.cookieStatusChangeSubscription = this.ccService.statusChange$.subscribe(
      (event: NgcStatusChangeEvent) => {
        this.hasConsented = event.status === this.ccService.getStatus().allow;
      });
  }

  ngOnDestroy() {
    this.cookieStatusChangeSubscription.unsubscribe();
  }
}

My plan was to call this service from any component where I need to check the status, like in my footer where I have Google Maps displayed:

@Component({
  selector   : 'app-footer',
  templateUrl: './footer.component.html',
  styleUrls  : ['./footer.component.css']
})
export class FooterComponent {
  hasConsented = false;

  constructor(
    private cookieCheckService: CookieCheckService
  ) {
    this.hasConsented = cookieCheckService.hasConsented;
  }
}

When I click on allow, I want to show my Google Maps widget using ngIf, but I'm not getting any value from my service - even initially. What am I doing wrong here?

Update

Just to clarify: this.ccService.getStatus() is an interface that provides the following options:

export interface NgcCookieConsentStatus {
    allow?: 'allow';
    deny?: 'deny';
    dismiss?: 'dismiss';
}

Answer №1

There are a couple of issues that need to be addressed

  1. The lifecycle hooks like OnInit(), OnDestroy() are specifically designed for components and directives, not services.

  2. The asynchronous assignment of this.hasConsented in the service may require behavior modification. One workaround is to move everything to the constructor.

Consider the following suggestions

Service

@Injectable()
export class CookieCheckService {
  public hasConsented = false;
  private cookieStatusChangeSubscription: Subscription;

  constructor(private ccService: NgcCookieConsentService) {
    if (this.ccService.hasConsented()) {
      this.hasConsented = true;
    }

    console.log(this.hasConsented);

    this.cookieStatusChangeSubscription = this.ccService.statusChange$.subscribe(
      (event: NgcStatusChangeEvent) => { this.hasConsented = event.status === this.ccService.getStatus().allow; }
    );
  }
}

Update

To update the changes to hasConsented (service) in the component, consider using an RxJS BehaviorSubject. Also, provide { providedIn: 'root' } to the @Injectable decorator of the service to ensure it remains a singleton throughout the app.

Service

import { BehaviorSubject } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class CookieCheckService {
  private hasConsentedSource = new BehaviorSubject<boolean>(false);

  public get hasConsented() {
    return this.hasConsentedSource.asObservable();
  }

  constructor(private ccService: NgcCookieConsentService) {
    if (this.ccService.hasConsented()) {
      this.hasConsentedSource.next(true);
    }

    console.log(this.hasConsented);

    this.ccService.statusChange$.subscribe(
      (event: NgcStatusChangeEvent) => { 
        this.hasConsentedSource.next(event.status === this.ccService.getStatus().allow); 
      }
    );
  }
}

You can then subscribe to it in the component.

Component

@Component({
  selector   : 'app-footer',
  templateUrl: './footer.component.html',
  styleUrls  : ['./footer.component.css']
})
export class FooterComponent {
  hasConsented = false;

  constructor(private cookieCheckService: CookieCheckService) {
    this.cookieCheckService.hasConsented.subscribe(
      status => { this.hasConsented = status }
    );
  }
}

Now, the hasConsented value in the component will dynamically update whenever a new value is pushed to the hasConsented value in the service.

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

Having trouble utilizing a custom array of objects in TypeScript and React?

After rendering a Functional Component that retrieves a list of objects, I successfully run a foreach loop with it. However, when I attempt to make http requests with each object to create a new array, something seems off. The formatting appears to be inco ...

What is the best way to showcase one object per day when I have an array of 30 objects in Ionic 4?

I'm looking to showcase a different quote in my app every day for 30 days using an array of 30 quotes. How can I achieve this daily quote rotation in Ionic 4? ...

How to Change a Property in a Child DTO Class in NestJS with Node.js

I am working with enums for status: export enum Status { Active = "Active", Inactive = "Inactive", } Additionally, I have a UserStatus enum: export enum UserStatus { Active = Status.Active, }; There is also a common dto that inc ...

Sending a POST request that is attempting to insert empty values into an MS SQL database

Here is the code I am working with - onSubmit(){ var headers = new Headers(); headers.append('Content-Type', 'application/x-www-form-urlencoded'); let postParams = { firstName : this.firstName, lastName : this.lastNa ...

Issue TS1127: Incorrect character detected while executing Karma tests in Angular 7

Encountering an issue with error TS1127: Invalid character in the Visual Studio Code terminal while running a Karma test for an Angular 7 app. CLI version - 7.3.9 There is only one Karma test specification in the app. (Removed all auto-generated spec files ...

Dynamic TypeScript class constructor argument typing determined by user input

I am working on creating a dynamic class that can adapt its argument properties based on a certain value. To illustrate this concept, let's consider a simple example: Imagine I have a class called Customizer, and depending on the value of the mode pr ...

Removing multiple items from a list in Vue JS using splice function

I have a problem with my app's delete feature. It successfully deletes items from the database, but there seems to be an issue in the front-end where I can't remove the correct items from the list. Check out this demo: https://i.sstatic.net/eA1h ...

Utilizing the Docker COPY command to exclusively transfer files of a specific file type extension

I have been working on implementing a new build process for one of our Angular applications. In order to reduce the bundle size, I have included a build step that involves gzipping all the files in the dist folder after the build process. After the build, ...

Tips for Passing On Parent tabindex Value to Children

Is there a way to propagate a parent's tabindex value to all of its children without individually setting tabindex for each child? Here is an example code snippet: <div id="app"> <div tabindex="2" class="parent-sec ...

handle HTTP errors within Observable.interval()

I have a block of code that runs every hour to a specific URL. Currently, if the URL is not found or returns a 500 error, I receive the error message. The application utilizes service workers, and functions properly when a valid URL is provided, triggering ...

In Angular 4 applications, all vendor CSS files are converted into style tags at the beginning of the HTML document

In my Angular 4 project, I have integrated Bootstrap, Fontawesome, and some custom CSS. However, all these styles are rendering as separate tags at the top of my index.html file. I would like them to be combined into a single bundled CSS file for better ...

Is there a way to utilize an Angular Material checkbox without any extra gaps or spacing?

Currently, I am working with Angular Material and trying to figure out how to remove the default spacing around the checkbox. The checkboxes in Angular Material are typically surrounded by some space (as shown in the image). Is there a simple way to elimin ...

The 'BaseResponse<IavailableParameters[]>' type does not contain the properties 'length', 'pop', etc, which are expected to be present in the 'IavailableParameters[]' type

After making a get call to my API and receiving a list of objects, I save that data to a property in my DataService for use across components. Here is the code snippet from my component that calls the service: getAvailableParameters() { this.verifi ...

Divide a given number of elements within an array of arrays

Presented below is an array: [ { "id": "34285952", "labs": [ { "id": "13399-17", "location": "Gambia", "edge": ["5062-4058-8562-294 ...

My approach to retrieving data from Firebase and converting it into an array of a specific type

Recently, I made the decision to expand my iOS application to also function as a web app. Although the implementation seems to be working, I am unsure if it is done correctly. I would appreciate it if someone could confirm if the implementation is correct. ...

Reference loss occurs in Angular Ionic when using @ViewChild

This situation is straightforward I am dealing with a reference in this format @ViewChild('myElement') myElementVar : SomeClass; The element I am referencing appears like this <element #myElement *ngIf="someBoolean"></element> As ...

Configuring NestJs with TypeORM asynchronously

I am currently facing an issue while implementing the @nestjs/typeorm module with async configuration. In my app.module.ts, I have the below setup: @Module({ controllers: [ AppController, ], exports: [ConfigModule], imports: [ ConfigModule ...

There seems to be a compatibility issue between Angular 16 and Bootstrap 5 styling

In my angular.json, I have defined my styles in the following way: "styles": [ { "input": "node_modules/bootstrap/dist/css/bootstrap.min.css", "bundleName": "ltrCSS" }, { "input": "node_mod ...

Button for saving content located in expo-router header

I am a beginner in react native and I am attempting to connect a save button in a modal header using expo-router. I have managed to make the button work within the modal itself, but I would like it to be located in the header set by expo-router. It doesn&a ...

Bringing in External Components/Functions using Webpack Module Federation

Currently, we are experimenting with the react webpack module federation for a proof of concept project. However, we have encountered an error when utilizing tsx files instead of js files as shown in the examples provided by the module federation team. We ...