Home > Software engineering >  How to send data from one routed component to another
How to send data from one routed component to another

Time:08-10

I am trying to send data from one routed component to another using RxJS Subject by the click of a button. The value is showing in console inside subscription but is not reflecting in the template/view.

Also, is using a subject the right way of sharing data between routed components, if not then what should I use?

StackBlitz link: https://stackblitz.com/edit/angular-ivy-g2zkwy?file=src/app/result/result.component.ts

home.html

<input #input placeholder="Enter something">
<button (click)="onSubmit(input.value)">Submit</button>

home.ts

import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { SubjectService } from '../subject.service';

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

  constructor(private router: Router, private ser: SubjectService) { }
  
  
    onSubmit(value: string) {
      console.log(value);
      this.ser.send(value);
      this.router.navigate(['result']);
      
  }

}

result.ts

import { Component, OnInit } from '@angular/core';
import { SubjectService } from '../subject.service';

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

  constructor(private ser: SubjectService) { }

  data = 'Data before it has changed';

  ngOnInit(): void {
    console.log('result');
    
    this.ser.source$.subscribe((message) => {
      this.data = message;
      console.log('Inside subcription:'   this.data);
    });

  } 

}

result.html

<p>Result page: </p>
<p>Data : {{data}}</p>

SubjectService.ts:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class SubjectService {

  constructor() { }
  private source = new Subject<any>();
  source$ = this.source.asObservable();

  send(message : string){
    this.source.next(message);
  }
 
}

App.component.html

<ul>
   <li><a routerLinkActive="active" routerLink="/home">Home</a></li>
  <li><a routerLinkActive="active" routerLink="/result">Result</a></li>
</ul>

<p>Router Outlet: </p>
<router-outlet></router-outlet>

App-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { ResultComponent } from './result/result.component';

const routes: Routes = [
  { path: 'result', component: ResultComponent },
  { path: 'home', component: HomeComponent },
  { path: '', redirectTo:'home', pathMatch:'full'}

];

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

The data variable is not updating in the result page.

CodePudding user response:

The problem is that you're firing the source$ observable before the results view is even initialized. If you start on your home view and enter a value you will not see the Here it is updating log in the console.

You don't really need a subject for your example, a simple service that holds your shared data in a property is plenty enough:

import { Injectable } from '@angular/core';

    @Injectable({
      providedIn: 'root',
    })
    export class SubjectService {
      public value: string | null = null;
    }

You can update this property by assigning it a value, e.g.

onSubmit(value: string) {
    this.ser.value = value;
    this.router.navigate(['result']);
  }

and in your results page you can define a getter to the service variable, which will always return the current value:

  public get data() {
    return this.ser.value || 'Value is empty';
  }

Stackblitz demo

  • Related