J'ai un composant de détail de cours qui contient des données (cours nommé) de mon application dorsale et je souhaite transmettre ces données à un autre composant (cours-play) qui n'est pas lié au composant. Je veux afficher les mêmes données que j'ai obtenues de mon backend dans ces deux composants. Ce sont les fichiers pertinents:
app-routage-module:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CourseListComponent } from './courses/course-list/course-list.component';
import { CourseDetailComponent } from './courses/course-detail/course-detail.component';
import { CoursePlayComponent } from './courses/course-play/course-play.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
const appRoutes: Routes = [
{ path: '', redirectTo: '/courses', pathMatch: 'full' },
{ path: 'courses', component: CourseListComponent, pathMatch: 'full' },
{ path: 'courses/:id', component: CourseDetailComponent, pathMatch: 'full'},
{ path: 'courses/:id/:id', component: CoursePlayComponent, pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent, pathMatch: 'full' }];
@NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
cours/cours (interface)
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;
}
courses/course.service:
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
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{
constructor(private http: HttpClient) { }
private url = 'http://localhost:3000/courses';
private courseUrl = 'http://localhost:3000/courses.json';
// 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));
}
}
cours/cours-detail/cours-detail.ts:
import { Component, OnInit, Pipe, PipeTransform } from '@angular/core';
import { ActivatedRoute, Router, Routes } from '@angular/router';
import { ICourse } from '../course';
import { CourseService } from '../course.service';
@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) {
}
ngOnInit() {
const id = +this.route.snapshot.paramMap.get('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);
}
onBack(): void {
this.router.navigate(['/courses']);
}
}
courses/course-play/course-play.ts:
import { Component, OnInit} 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';
@Component({
selector: 'lg-course-play-course-play',
templateUrl: './course-play.component.html',
styleUrls: ['./course-play.component.sass']
})
export class CoursePlayComponent implements OnInit {
courseId: number;
errorMessage: string;
private sub: any;
constructor(private courseService: CourseService,
private route: ActivatedRoute,
private router: Router) {
}
ngOnInit() {
}
onBack(): void {
this.router.navigate(['/courses/:id']);
}
}
Sans extraire aucune autre bibliothèque, Angular spécifie quelques façons pour les composants de communiquer entre eux. Documentation
Étant donné que vos composants ne sont pas des parents/enfants mais des frères et soeurs, les options sont encore plus limitées.
D'après le code que vous avez montré, je pense que le n ° 2 est votre meilleure option. Ainsi, vous pouvez ajouter une propriété à votre CourseService
:
public selectedCourse: ICourse;
Ensuite, vous pouvez y accéder dans les deux composants:
this.courseService.selectedCourse;
Les problèmes de cette approche sont que vous devez ensuite gérer un état psuedo-global et vous assurer que le service est uniquement injecté/fourni (sinon, chaque composant obtiendra sa propre instance du service et vous ne pourrez pas partager de données).
Comme indiqué dans un commentaire de Pavan sur la question, vous devriez probablement utiliser un Observable
et vous y abonner. Avec l'approche mentionnée ci-dessus, les composants ne recevront pas de notifications lorsque la valeur changera et devront vérifier de manière proactive les modifications en charge.
Si vous avez un identifiant sur votre chemin, essayez ceci
import { Component, OnInit} 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';
@Component({
selector: 'lg-course-play-course-play',
templateUrl: './course-play.component.html',
styleUrls: ['./course-play.component.sass']
})
export class CoursePlayComponent implements OnInit {
courseId: number;
errorMessage: string;
private sub: any;
constructor(private courseService: CourseService,
private route: ActivatedRoute,
private router: Router) {
}
ngOnInit() {
const id = +this.route.snapshot.paramMap.get('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);
}
onBack(): void {
this.router.navigate(['/courses/:id']);
}
}