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

Learn how to retrieve images from the web API at 'https://jsonplaceholder.typicode.com/photos' and showcase them on a webpage using Angular10

Using the API "https://jsonplaceholder.typicode.com/photos", I have access to 5 properties: albumId: 1 id: 1 thumbnailUrl: "https://via.placeholder.com/150/92c952" title: "accusamus beatae ad facilis cum similique qui sunt" url: "https://via.placeh ...

Tips for generating a fixed-length array from multiple arrays with different lengths, focusing on selecting items from each array according to their significance

In order to create a quiz, I am looking to extract 'questions' from various 'topic' arrays. These topics are selected based on the user's preference and are used to populate a question bank for a 20-question quiz. The topics rated ...

Efficient management of npm dependencies versioning using Git workflow with Angular

In my Angular project, we combine multiple locally created artifacts that are published to the npm repository. Within the "dependencies" section of my app's package.json file, I include the following: "@k/e-lib": "^0.3.0", "@k/et-lib": "^0.3 ...

Access information from your own API endpoint and incorporate it with an interface

Trying to retrieve the json-data from an api-server but encountering difficulties adding it to the variable. The error received is: Type is missing the following properties from Type "Observable" missing the properties from type "GAMELIST[]": "length, p ...

The error message "TypeError: (0 , N.createContext) is not a function" indicates that

I'm currently in the process of developing a cutting-edge application using Next.js 14, TypeScript, and Telegram Open Network. However, I've hit a roadblock while attempting to incorporate the TONConnectUIProvider at the root of my app. Upon run ...

Using ThreeJS to Apply Dual Materials to a Mesh Entity

With ThreeJS, it's possible to incorporate more than one material into an Object3D/Mesh as stated in the documentation. You can either utilize a single Material or an array of Material: Class declaration and constructor for Mesh TypeScript file (exce ...

Submitting a value to ngForm: A step-by-step guide

I am working on an ngForm within Angular Material that contains several input fields. I want to include a new field called total in the submission, but this field is not an input field. It should be a readonly field and its value needs to come from the Typ ...

Having trouble implementing the ternary operator (?) in TypeScript within a Next.js project

Trying to implement a ternary operator condition within my onClick event in a Next.js application. However, encountering an error indicating that the condition is not returning any value. Seeking assistance with resolving this issue... https://i.stack.img ...

"Why Injecting HttpClient in Angular 4 can be a Game-Changer? Let's

According to the documentation provided by Angular, the HttpClient is injected into the main app component. However, I came across another guide that simply referred to this as a "favorable" practice without providing any explanation. @Component(...) expo ...

Encountering issues with retrieving application setting variables from Azure App Service in a ReactJS TypeScript application resulting in '

My dilemma lies in my app setup which involves a Node.js runtime stack serving a ReactJs Typescript application. I have set some API URLs in the application settings, and attempted to access them in ReactJs components using process.env.REACT_APP_URL, only ...

Firebase Authentication error code "auth/invalid-email" occurs when the email address provided is not in a valid format, triggering the message "The email address is

Currently, I am working on integrating Firebase login and registration functionality into my Angular and Ionic 4 application. Registration of user accounts and password retrieval are functioning properly as I can see the accounts in my Firebase console. Ho ...

Issues with unresponsive buttons in AngularJs

In creating a basic registration page, I encountered a strange issue with the button functionality. Whenever I attempt to submit the form, an error should be logged to the console. However, the buttons on the registration page appear to be inactive - it se ...

When using Router.push() in next.js, the error TypeError: products.map is not a function may arise

Currently, I am implementing redux saga in my project. Here is how the state looks: const productList = useSelector((state: RootState) => state.productList); const { loading, error, products, page, pages } = productList; In the useEffect hook, I dispa ...

Combine all the missing observables in RxJS into a single array

In my code, I am creating a NavBar with items that may require fetching extra information from an API and adding it to the subtitle field. I want to transform this into an Observable<NavItem[]> so that it can be rendered using an Async Pipe. Curren ...

The utilization of a Typescript Generic for basic addition is not producing the desired results

This issue feels incredibly insignificant, but for some reason I can't seem to figure out why it's not functioning correctly. It seems like the return type should match since I am simply concatenating or adding based on whether it's a number ...

What are the counterparts of HasValue and .Value in TypeScript?

There is a method in my code: public cancelOperation(OperationId: string): Promise<void> { // some calls } I retrieve OperationId from another function: let operationId = GetOperationId() {} which returns a nullable OperationId, operat ...

Error encountered when extending Typography variant in TypeScript with Material UI v5: "No overload matches this call"

Currently, I am in the process of setting up a base for an application using Material UI v5 and TypeScript. My goal is to enhance the Material UI theme by adding some custom properties alongside the default ones already available. The configuration in my ...

Always deemed non-assignable but still recognized as a universal type?

I'm curious about why the never type is allowed as input in generic's extended types. For example: type Pluralize<A extends string> = `${A}s` type Working = Pluralize<'language'> // 'languages' -> Works as e ...

Detecting URL changes on new windows in Angular Typescript: How to do it?

I am currently working with the updated version of Angular 6. My task involves opening a new browser window based on user input, which includes a specific return URL. After the return URL is fully loaded, I need to access and extract a particular element f ...

Exploring the narrowing capabilities of TypeScript within while loops

When I write while loops, there are times when I know for sure that a certain value exists (connection in this case), but the control flow analysis is unable to narrow it down. Here's an illustration: removeVertex(vertex: string) { const c ...