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';
}