Using Angular 6 to Share Data Among Components through Services

I am facing an issue in my home component, which is a child of the Dashboard component. The object connectedUser injected in layoutService appears to be undefined in the home component (home userID & home connectedUser in home component logs); Is there something missing here?

home.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HomeRoutingModule } from './home-routing.module';
import { HomeComponent } from './home.component';

@NgModule({
    imports: [
          CommonModule,
          ReactiveFormsModule,
          HomeRoutingModule,
          FormsModule
    ],
    declarations: [
        HomeComponent
        ],
    providers: [

    ]
  })
  export class HomeModule {}

dashboard.component.ts

import { Component, OnInit } from '@angular/core';
import { UserConnected } from 'src/app/models/userConnected';
import { LayoutService } from '../services/layout.service';

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {

  currentDate: String;
  userSaml = new UserConnected();
  constructor(public layoutService: LayoutService) { }

  ngOnInit(): void {
  
    var today = new Date();
    this.currentDate = today.getDate() + '/' + (today.getMonth() + 1) + '/' + today.getFullYear();

    this.layoutService.getConnectedUser().subscribe(

      (data) => {
        this.userSaml = data;
        this.layoutService.connectedUser.matricule = this.userSaml.matricule;
        this.layoutService.connectedUser.profil = this.userSaml.profil;
        this.layoutService.connectedUser.uid = this.userSaml.uid;
        this.layoutService.connectedUser.username = this.userSaml.username;
        this.layoutService.connectedUser.city = this.userSaml.city;
      },
      (err) => {
        throw err;
      }
    );

  }

}

app-routine.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AppComponent } from './app.component';
import { DashboardComponent } from './shared/layout/dashboard/dashboard.component';

export const routes: Routes = [
  {
    path: '',
    component: DashboardComponent
    , children: [
      {
        path: '',
        loadChildren: './home/home.module#HomeModule'
      },
      {

        path: 'rapport',
        loadChildren: '../rapport/rapport.module#RapportModule'
      },
      {
        path: 'admin',
        loadChildren: './admin/admin.module#AdminModule'
      }
    ]
  }];

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

home.component.ts

import { Component, OnInit } from '@angular/core';
import { LayoutService } from '../shared/layout/services/layout.service';
import { UserConnected } from '../models/userConnected';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor(public layoutService: LayoutService) { }
  userID: string;
  userExists : boolean = false;
  connectedUser = new UserConnected;
  ngOnInit() : void {
    this.connectedUser = this.layoutService.connectedUser;
    console.log("home connectedUser" + JSON.stringify(this.connectedUser));
    this.userID = this.connectedUser.uid;
    console.log("home userID" + this.userID);

    this.adminService.verifyUser(this.userID)
      .subscribe(
        (data) => {
          this.userExists = true;
        },
        (err) => {
          this.userExists = false;
        }
      );
  }

}

layoutService

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '../../../../environments/environment';
import { UserConnected } from 'src/app/models/userConnected';


@Injectable({
  providedIn: 'root'
})
export class LayoutService {
  
  connectedUser : UserConnected;

  constructor(private http:HttpClient) { }

   getConnectedUser(){
    return this.http.get<UserConnected>(environment.RAA_ROOT + '/connectedUser');
  }

}

Answer №1

connectUser within the LayoutService module seems to be the root cause of the issue you are facing.

connectedUser : UserConnected = new UserConnected();

This code snippet will ensure that you have the correct object type from the UserConnected class, preventing any errors during access. Keep on coding happily! :)

Answer №2

If you want to make changes, start by modifying the line in your HomeComponent like this:

this.connectedUser = this.layoutService.getConnectedUser()

Instead of using

this.connectedUser = this.layoutService.connectedUser;
, which will return undefined if not assigned in your layoutService.

Remember that http.get is asynchronous and returns an observable. You need to subscribe to it to use it in your component or utilize asyncPipe if you plan to use it in your template.

To proceed:

this.layoutService.getConnectedUser().subscribe((connectedUser) => { this.connectedUser = connectedUser; })

For further explanation, visit: https://angular.io/tutorial/toh-pt6

Answer №3

If you want to enhance the performance of your service, consider updating the implementation and implementing a more efficient caching system:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '../../../../environments/environment';
import { UserConnected } from 'src/app/models/userConnected';


@Injectable({
  providedIn: 'root'
})
export class LayoutService {
  
  private _cachedConnectedUser: UserConnected;

  constructor(private http:HttpClient) { }

   getConnectedUser(): Observable<UserConnected> {

    if (this._cachedConnectedUser ) {
      return of(this._cachedConnectedUser);
    }

    return this.http.get<UserConnected>(environment.RAA_ROOT + '/connectedUser')
     .map(response =>  {
       this._cachedConnectedUser = response.body;
       return this._cachedConnectedUser;
     });
  }    
}

Once implemented, you can simply call layoutService.getConnectedUser() to retrieve the object without managing additional local variables.

For further optimization of the caching mechanism, refer to this informative article: here

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

I attempted to unsubscribe from an observable in Angular, but I encountered an error stating that the unsubscribe function does not exist

Here is the code snippet from a components.ts file in an Angular project. I encountered the following error during compilation: ERROR merge/merge.component.ts:75:12 - error TS2551: Property 'unsubscribe' does not exist on type 'Observable& ...

Having trouble getting Typescript code to function properly when using commonjs style require statements

I am completely new to Typescript, Node.js, and Express. Following the instructions outlined in this tutorial (https://www.digitalocean.com/community/tutorials/setting-up-a-node-project-with-typescript), I set up my project exactly as described there. The ...

The CSS variables set within the :root section of styles.scss are not recognized as valid

Trying to implement global colors using CSS variables in my Angular 11 app. The styles.scss file contains: :root{ --primary : #0b68e8; --secondary:#ABCFFF; } .test-class{ background: var(--primary); } However, when applying this class in one ...

Tips for checking dropzone functionality during development

I'm currently working on an Angular 5 application and incorporating dropzonejs (the angular wrapper) into it. However, as I am not the backend developer, I do not have full visibility into how the backend has been developed. Currently, CORS is being ...

Discover how to retrieve service response data from an API and populate it into the Select Option with Angular 2

Api.services.ts getListOfNames() { return this.http.get(this.BaseURL + 'welcome/getnama') .pipe(map(response => { return response; })); } After making the API call, I receive the following resp ...

The call stack size has reached its maximum limit;

Encountering an issue with the use of componentDidMount(). This method is intended to display a Tooltip by utilizing the function _getContentTooltip(). However, the problem arises as it triggers the error message common.js:444 RangeError: Maximum call st ...

Tips for showcasing images stored in Azure Blob storage

Currently, I am developing an application that requires loading images from a web novel stored in Azure Storage Accounts as blobs. While I have enabled anonymous reads to show the image upon request successfully via a web browser or Postman, I am facing an ...

Intellisense in VS Code is failing to provide assistance for data within Vue single file components

I am working with a simple code snippet like this However, within the method, the variable 'name' is being recognized as type any. Interestingly, when I hover over 'name' in the data, it shows up as a string. The Vetur plugin has alre ...

What is the best way to rid ourselves of unwanted values?

In the laravel-vue-boilerplate package, there is a User CRUD feature. I duplicated this functionality to create an Item CRUD by making some changes and adjustments. Everything is working fine except for one issue: after editing an item, when trying to add ...

Angular 10 - Understanding the R3InjectorError in AppModule related to Window constant injection

I'm attempting to access the window object in Angular using a service that can be injected. import { Injectable } from '@angular/core'; function _window(): any { return window; } @Injectable({ providedIn: 'root' }) export cla ...

Converting a promise of type <any> to a promise of type <entity>: A beginner's guide

As a newcomer to TypeScript and NestJS, I am wondering how to convert Promise<any[]> to Promise<MyEntity[]> in order to successfully execute the following code: const usersfromTransaction = this.repoTransaction .createQueryBuilder() ...

What is the method for using the pipe to convert currency rates to a specific currency type?

I am working on a project where I need to display currency rates in the selected currency type all over the page. I have a dropdown with various currency types and want to dynamically update the rates based on the selected currency. After some research, I ...

When a ListView item is clicked, a label will display text with text wrapping specific to the selected item in the list

Within the listview items, there is a label that should expand when clicked. For example, initially it only shows one line of text. Upon clicking on the label, it should expand to show 10 lines of text. Current Issue: At present, when I click on the firs ...

Angular 4 - capturing and resending HTTP requests post-login

My HttpInterceptor is designed to monitor specific JWT token events (token_expired, token_not_provided and token_invalid) that can occur at various stages within the workflow. These events may be triggered when a user switches routes OR when an AJAX reque ...

Error in Angular 2 Form Validation

Take a look at this simple form example: <form [ngFormModel]="myForm"> <input type="text" [ngFormControl]="fname" placeholder="First Name"/> <div *ngIf="fname.errors.minlength">First name should be at least 2 characters&l ...

I'm working on separating the functionality to edit and delete entries on my CRM model, but I'm having trouble finding a way to connect these buttons with my data fields

I am encountering some difficulties while trying to implement separate functionality for editing and deleting items on my CRM model. I have already created the necessary API in Angular, but I am struggling to bind these buttons with my field. Any assistanc ...

When TypeScript generator/yield is utilized in conjunction with Express, the retrieval of data would not

Trying to incorporate an ES6 generator into Express JS using TypeScript has been a bit of a challenge. After implementing the code snippet below, I noticed that the response does not get sent back as expected. I'm left wondering what could be missing: ...

Resolving callback definition issue: Can be assigned to constraint, yet may be instantiated with a distinct subtype. ( TS 2345 )

Seeking insight on the typing issue causing a compiler error in the code snippet below. Any suggestions for maintaining type-safety without resorting to any or as? Avoiding these workarounds is important to me. The challenge lies in the evidence() call, c ...

Error encountered in Angular: Trying to assign a value to an empty string array results in the error message "Type (string | undefined)[] is not assignable to

Struggling with an issue in my Angular App - trying to assign a value to an empty array Current environment: node 12.18.4 npm 6.14.8 Here's my typescript.ts code snippet: import { Injectable } from "@angular/core"; import { Product } from ...

How can I best declare a reactive variable without a value in Vue 3 using TypeScript?

Is there a way to initialize a reactive variable without assigning it a value initially? After trying various methods, I found that using null as the initial value doesn't seem to work: const workspaceReact = reactive(null) // incorrect! Cannot pass n ...