Transferring Information Between Components

After logging into my login component, I want to pass data to my navbar component but unfortunately, my navbar content does not update.

The navbar component is located in the app-module while the login component is in a separate module.

I attempted to use services to share the data between components.

In my login component, which resides in a different module:

export class LoginComponent {
  userCredentials;
  constructor(
    private readonly _authService: AuthService,
  ) {

  }

  login() {
    this._authService.auth(this.userCredentials)
      .subscribe(
        (response: any) => {

            const dataForm = {
              usuario: response.user,
              rol: this.response.role,
            };
            this._authService.setSession(response);
        },
        error => {
          console.log(error);
        }
      );
  }
}

In my NavBarComponent, found within the app-module:

export class NavbarComponent  {

  isLogged = false;
  susbscription: Subscription;
  constructor(
    private readonly _authService: AuthService,
  ) {
    this.subscription = this._authService
      .changeState$
      .subscribe(
        (isLogged) => {
          this.isLogged = isLogged;

        },
        error => console.log(error)
      );
  }
}

Here is the HTML for my NavBar component:

<mat-toolbar color="primary">
    <mat-toolbar-row>
      <span>SUPERMERCADO</span>
      <span class="spacer"></span>
      <div *ngIf="!isLogged">
        <button mat-button 
          Login
        </button>
      </div>
      <div *ngIf="isLogged">
        <p>Welcome</p>
      </div>
    </mat-toolbar-row>
  </mat-toolbar>

The AuthService, which is not part of the app-module:

@Injectable()
export class AuthService {
  protected url = environment.url;
  protected model = '/user';

  isLogged = false;
  private changeState = new Subject<boolean>();
  changeState$ = this.changeState.asObservable();

  constructor(
    private readonly _router: Router,
    protected readonly httpclient: HttpClient,
  ) {
  }

  setSession(data: any) {
    this.isLogged = true;
    this.changeState.next(this.isLogged);
  }

  auth(dataForm: any): Observable<any> {
    const url = `${this.url}${this.model}/login`;
    return this.httpclient.post(url, dataForm);
  }

}

This project is built using Angular 8.2.0.

Answer №1

Is the LoginComponent included in a lazy-loaded Module?

If so, remember to add the providedIn: 'root' property to the AuthService:

@Injectable({
  providedIn : 'root'
})

Do not forget to remove it from the providers list of the Module.

If your LoginComponent is not lazy-loaded, ensure that you only import the AuthService once in AppModule to avoid multiple instances.

If you want AuthService to be part of a module, consider using the forRoot pattern to make sure services are imported only once:

@NgModule({
  // declarations, imports and exports only
})
export class SharedModule {

  static forRoot(): ModuleWithProviders {
  return { 
    ngModule: SharedModule,
    providers: [// your services]
  }
}

@NgModule({
  imports: [SharedModule.forRoot()]
})
export class AppModule {}

In Angular 8, another option is:

@Injectable({
  providedIn: SharedModule
})
export class AuthService

This ensures that the same instance of AuthService is available to both AppModule and the Module where the LoginComponent is located.

If the above solutions do not resolve the issue, there might be an problem where NavBarComponent subscribes to the changeState$ observable after it emits. In such case, changing changeState to a BehaviorSubject will ensure that NavBarComponent receives the last emitted value when subscribing.

Answer №2

Two possible reasons why your code may not be functioning as expected are:

  1. The issue could be that the changeState subject emits data before the navbar component subscribes to it. It seems that the navbar component is not yet loaded when you are on the login page. In your LoginComponent, you emit the data first, and then when the NavbarComponent loads, you subscribe to the observable that just emitted. However, using a Subject means you will not receive the last emitted value. To address this, you can utilize a BehaviorSubject, which retains the last emitted value for new subscribers.

Subject vs BehaviorSubject

const s = new Subject();

s.next('not seen...');
s.next('not seen...');
s.next('not seen...');

s.subscribe(d => console.log('SUBSCRIBER 1: ', d))

// You must first subscribe, as the `Subject` does not hold any values on its own

s.subscribe(d => console.log('SUBSCRIBER 2: ', d))

// `Subscriber 1` will also receive those
s.next('value1 !!');
s.next('value2 !!');

/* 
SUBSCRIBER 1: value1 !!
SUBSCRIBER 2: value1 !!
SUBSCRIBER 1: value2 !!
SUBSCRIBER 2: value2 !!
*/


const bs = new BehaviorSubject(null);

bs.next('not seen');

// It will retain only the last value for new subscribers
bs.next('hmmm!!')

bs.subscribe(v => console.log('subscriber 1 of BS: ', v))

bs.next('value1!')
bs.subscribe(v => console.log('subscriber 2 of BS: ', v))

/* 
subscriber 1 of BS: hmmm!!
subscriber 1 of BS: value1!
subscriber 2 of BS: value1!
*/

Here is a StackBlitz demo if you want to explore.

Therefore, by replacing your Subject with a BehaviorSubject(null), it should resolve the issue.

  1. Another potential reason is that the AuthService is not part of the AppModule. This could result in not obtaining a singleton instance. Adding the
    Injectable({ providedIn: 'root' })
    decorator to your AuthService class (which also makes the service tree-shakable) should help rectify this issue.

Answer №3

Utilize Local Storage to store data and access it from any component by creating a shared service for fetching information through string interpolation. Implement the following Service Part:

getUserInfo() {
   const savedCredentials = localStorage.getItem(credentialsKey);
    return JSON.parse(savedCredentials);
  }

In the Component Part, call the method like this:

 this.currentUser = this.authService.getUserInfo();

Then you can access the data as follows:

this.currentUser.BusinessDate

Answer №4

Component Interaction

import { Component, OnInit, ViewChild} from '@angular/core';
import { DataService } from "src/app/service/data.service";
@Component( {
    selector: 'app-sideWidget',
    templateUrl: './sideWidget.html',
    styleUrls: ['./linked-widget.component.css']
} )
export class SideWidget{

constructor( private LWTableColumnNames: DataService ) { 

}

ngOnInit() {
 this.LWTableColumnNames.refLWTableColumnNames =  "patient"; //passing value via data service

}    
}

Data Service Definition

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable()
export class DataService {
    refLWTableColumnNames: string;//data object declaration
}

Receiving Component

import { Component, OnInit } from '@angular/core';
import { DataService } from "src/app/service/data.service";

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

    constructor(private LWTableColumnNames: DataService) { }

    ngOnInit() {
    console.log(this.LWTableColumnNames.refLWTableColumnNames); //output will be the string "patient"
    }

}

Check out this Stackbliz demo to see how values can be passed between sibling components as well.

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

Setting up the primary and thumbnail Swiper in Angular can be a bit tricky, especially when the initialization is set to false. This tutorial focuses on initializing Swiper 11.0

I have incorporated Swiper into several of my components, and I am facing an issue when Angular routing changes, especially with routeParams like /route/:id – it doesn't work correctly. To tackle this problem, I decided to implement ngZone. Although ...

ngDraggable does not function properly when the dropzone is larger and includes a scrollbar on the body

Here is a demo showing the issue: The current version 0.1.11 does not support drag and drop functionality. This is how I have implemented the code: <uib-accordion-group is-open="category.open" name="category-{ ...

Tips for incorporating Legacy pre-configured ESLint settings into your Angular 15 project and upgrading to Angular 16

As I was in the process of upgrading my app from version 15 to version 16, I came across some linting errors. It turns out that certain plugins have been removed from angular-eslint starting from version 16. The solution provided is to manually re-add thos ...

The Angular Universal error arises due to a ReferenceError which indicates that the MouseEvent is not

I am encountering an error while trying to utilize Angular Universal for server-side rendering with the command npm run build:ssr && npm run serve:ssr. This is being done in Angular8. /home/xyz/projects/my-app/dist/server/main.js:139925 Object(tslib__WEB ...

The functionality of verifying the type of an item in a list using Typescript is not functioning

In my TypeScript code, I am working with a type called NameValue and another one called MixedStuff. type NameValue = { name: string; value: string }; type MixedStuff = NameValue | string; function stripTwoChars(stuffs: MixedStuff[]): string { let st ...

Retrieving the name of the current page in ionViewCanEnter

While working with Ionic 2, I am currently facing a challenge in identifying the name of the page that triggered the navigation (PUSHER) before entering the destination page (PUSHEE). Within the PUSHEE page, I have an ionViewCanEnter function where I need ...

Verify if an array contains a specific string while disregarding any additional letters within that string

Let's say I have a variable: var url = "/login/user"; Along with an array: var x = ["login", "resetpassword", "authenticate"]; My goal is to check if the url string exists within the array. The issue arises because the url contains additional char ...

Cluster multiple data types separately using the Google Maps JavaScript API v3

I am looking to implement MarkerClusterer with multiple markers of various types and cluster them separately based on their type. Specifically, I want to cluster markers of type X only with other markers of type X, and markers of type Y with other markers ...

Demystifying the Mechanics of RxJS Subscriptions during an HTTP Request

export class VendorHttpService { result = '0'; constructor(private http: HttpClient, private global: GlobalService) { } getProfileStatus(uid: String): string { this.http.get(this.global.getUrl()+"/vendor/profile-status/"+uid) ...

Vue and TypeScript: The elusive 'exports' remains unidentified

Since switching my App.vue to utilize typescript, I am facing a compiler error: [tsl] ERROR in \src\main.ts(2,23) TS2304: Unable to locate the name 'exports'. If I have vue-serve recompile after making changes, I encounter t ...

Can you explain the correct method for assigning types when destructuring the `callbackFn.currentValue` in conjunction with the `.reduce()` method? Thank you

I'm working with an array of arrays, for example: const input = [['A', 'X'], ['B', 'Y'],...]; In addition to that, I have two enums: enum MyMove { Rock = 'X', Paper = 'Y', Scis ...

Is there a way to attach a Blob/File array to formData in typescript?

If I didn't have an ARRAY of files, this method would work perfectly. However, it needs to be in the form of an Array. let file1 = new File([""], "filename"); let file2 = new File([""], "filename"); let fi ...

What is the process for utilizing ts-node ESM in conjunction with node modules?

Disclaimer: I understand that the question below pertains to an experimental feature. I have initiated a thread on the ts-node discussion forum. Nonetheless, I believe that posting on StackOverflow will garner more visibility and potentially result in a qu ...

Issue encountered when running a minification build on Angular 5

After successfully updating my Single Page Application (SPA) from Angular 4 to Angular 5 along with all dependencies, everything seemed to be working well. Both the development and production builds were functioning without any errors or warnings. However ...

Encountering an issue: JwPagination in angular 9 throws an error of "Cannot read property 'currentValue' of undefined"

Currently using Jw pagination with a page size that changes on 5, 10, or 15 using a dropdown. The Angular version being used is angular 9. The HTML code snippet for this functionality looks like: <div class="col-md-6"> <div ...

Maintaining the order of the returned values type is crucial when working with mapped objects in Typescript

Currently, I am developing a basic mapper function for objects. This function is designed to take an array of object properties and then return an array containing the corresponding values of these properties. The function works as intended; however, I hav ...

Component presenting surprising results

Struggling to display data in an HTML component, I encountered a peculiar issue. Upon entering values for the first time, everything appears correctly. However, upon subsequent entries and retrievals, the second value is displayed twice, the third value th ...

The concept of Material Design: Utilizing a grid system with automatic card height

Is there a way to create a grid with cards that have auto height, similar to this example: I am currently using Material Design and Angular 4, but I am also open to solutions involving React or VueJS. I have tried using the flex-layout dependency, but I a ...

What's causing the subscription feature to malfunction in a fresh browser tab?

I am facing an issue with camera entries on an angular website. Whenever I click on an entry, a new window opens to display the camera livestream. However, I am having trouble with the subscribe functionality. Important note: Once the window is open, subs ...

WebStorm's TypeScript definitions are failing to function properly

I'm experiencing an issue with my three.js code and TypeScript definitions in settings. Despite enabling them, there doesn't seem to be any effect. I've downloaded everything and checked the necessary boxes, but nothing is changing. WebStorm ...