Reputation: 671
I'm trying to pass data between course-detail component and course-play component. I used shared service and BehaviorSubject. The data is passing correctly to course-detail through the service, and when go to course-play html page through course-detail html page it works just fine, but when I refresh the page, it's using the default id I gave courseId in the service. I need to find a way for the id to stay in the service all the time after getting it from course-play and just keep that update when I get another course id. Here's my code:
course.ts
export interface ICourse {
course_id: number;
title: string;
autor: string;
segments: ISegment[];
}
export interface ISegment {
segment_id: number;
unit_id: number;
unit_title: string;
name: string;
type: string;
data: string;
}
course.service
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';
import { Observable, throwError } from 'rxjs';
import { catchError, groupBy } from 'rxjs/operators';
import { ICourse } from './course';
// Inject Data from Rails app to Angular app
@Injectable()
export class CourseService{
// JSON url to get data from
private url = 'http://localhost:3000/courses';
private courseUrl = 'http://localhost:3000/courses.json';
// Subscribe data
private courseId = new BehaviorSubject(1);
public courseId$ = this.courseId.asObservable();
// here we set/change value of the observable
setId(courseId) {
this.courseId.next(courseId)
}
constructor(private http: HttpClient) { }
// Handle Any Kind of Errors
private handleError(error: HttpErrorResponse) {
// A client-side or network error occured. Handle it accordingly.
if (error.error instanceof ErrorEvent) {
console.error('An error occured:', error.error.message);
}
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong.
else {
console.error(
'Backend returned code ${error.status}, ' +
'body was ${error.error}');
}
// return an Observable with a user-facing error error message
return throwError(
'Something bad happend; please try again later.');
}
// Get All Courses from Rails API App
getCourses(): Observable<ICourse[]> {
const coursesUrl = `${this.url}` + '.json';
return this.http.get<ICourse[]>(coursesUrl)
.pipe(catchError(this.handleError));
}
// Get Single Course by id. will 404 if id not found
getCourse(id: number): Observable<ICourse> {
const detailUrl = `${this.url}/${id}` + '.json';
return this.http.get<ICourse>(detailUrl)
.pipe(catchError(this.handleError));
}
}
course-detail.component
import { Component, OnInit, Pipe, PipeTransform } from '@angular/core';
import { ActivatedRoute, Router, Routes } from '@angular/router';
import { ICourse } from '../course';
import { CourseService } from '../course.service';
// Course-detail decorator
@Component({
selector: 'lg-course-detail',
templateUrl: './course-detail.component.html',
styleUrls: ['./course-detail.component.sass']
})
export class CourseDetailComponent implements OnInit {
course: ICourse;
errorMessage: string;
constructor(private courseService: CourseService,
private route: ActivatedRoute,
private router: Router) {
}
// On start of the life cycle
ngOnInit() {
// get the current course id to use it on the html file
const id = +this.route.snapshot.paramMap.get('id');
// set curretn course Id in the service to use it later
this.courseService.setId(id);
this.getCourse(id);
}
// Get course detail by id
getCourse(id: number) {
this.courseService.getCourse(id).subscribe(
course => this.course = course,
error => this.errorMessage = <any>error;
)
}
// When we click the back button in browser
onBack(): void {
this.router.navigate(['/courses']);
}
}
course-play-component
import { Component, OnInit, Input} from '@angular/core';
import { ActivatedRoute, Router, Routes, NavigationEnd } from '@angular/router';
import { MatSidenavModule } from '@angular/material/sidenav';
import { ICourse } from '../course';
import { CourseService } from '../course.service';
// Couse-play decorator
@Component({
selector: 'lg-course-play-course-play',
templateUrl: './course-play.component.html',
styleUrls: ['./course-play.component.sass']
})
export class CoursePlayComponent implements OnInit {
errorMessage: string;
course: ICourse;
courseId: number;
constructor(private courseService: CourseService,
private route: ActivatedRoute,
private router: Router) {
courseService.courseId$.subscribe( courseId => {
this.courseId = courseId;
})
}
// On start of the life cycle
ngOnInit() {
// get the current segment id to use it on the html file
const segmentId = +this.route.snapshot.paramMap.get('id');
this.getCourse(this.courseId);
}
// Get course detail by id
getCourse(id: number) {
console.log(id);
this.courseService.getCourse(id).subscribe(
course => this.course = course,
error => this.errorMessage = <any>error;
)
}
// When we click the back button in browser
onBack(): void {
this.router.navigate(['/courses/:id']);
}
}
Upvotes: 3
Views: 15368
Reputation: 609
It is default behavior of BehaviorSubject. When ever you refresh page you will get default id from service. If you want to get your updated id, then store it in local storage/cookie and update your behavior subject from that value.
To store value in localStorage
when you update your id:
localStorage.setItem(key, value);
To get item from localStorage
:
localStorage.getItem(key);
And when page refresh, you need to read value from localStorage
and emit value to subscriber using next();.
Example:
this.your_service.your_behavior_subject.next(value_from_localstorage);
you need to emit in global component [app.component.ts]. So it is available through out your application
Upvotes: 1
Reputation: 4190
Need to set the initial state to read from local storage:
private myValue = JSON.parse(localStorage.getItem('myData')) as MyData;
and then seed the store:
public myData: BehaviorSubject<myData> = new BehaviorSubject(this.myValue);
To change or seed when there's no local storage, just use .next to add values to it.
Upvotes: 0