I have a questions about passing data in Angular.
First, I don't have a structure as <parent><child [data]=parent.data></child></parent>
My structure is
<container>
<navbar>
<summary></summary>
<child-summary><child-summary>
</navbar>
<content></content>
</container>
So, in <summary /> I have a select that do send value to <child-summary /> and <content />.
OnSelect method is well fired with (change) inside <summary /> component.
So, I tried with #Input, #Output and #EventEmitter directives, but I don't see how retrieve the event as #Input of the component, unless to go on parent/child pattern. All examples I've founded has a relation between component.
EDIT : Example with BehaviorSubject not working (all connected service to API works well, only observable is fired at start but not when select has value changed)
shared service = company.service.ts (used to retrieve company data)
import { Injectable } from '#angular/core';
import { Headers, Http, Response } from '#angular/http';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
#Injectable()
export class SrvCompany {
private accountsNumber = new BehaviorSubject<string[]>([]);
currentAccountsNumber = this.accountsNumber.asObservable();
changeMessage(accountsNumber: string[]) {
this.accountsNumber.next(accountsNumber);
}
private _companyUrl = 'api/tiers/';
constructor(private http: Http) { }
getSociete(): Promise<Response> {
let url = this._companyUrl;
return this.http.get(url).toPromise();
}
}
invoice.component.ts (the "child")
import { Component, OnInit, Input } from '#angular/core';
import { Headers, Http, Response } from '#angular/http';
import { SrvInvoice } from './invoice.service';
import { SrvCompany } from '../company/company.service';
#Component({
selector: 'invoice',
templateUrl: 'tsScripts/invoice/invoice.html',
providers: [SrvInvoice, SrvCompany]
})
export class InvoiceComponent implements OnInit {
invoice: any;
constructor(private srvInvoice: SrvInvoice, private srvCompany: SrvCompany)
{
}
ngOnInit(): void {
//this.getInvoice("F001");
// Invoice data is linked to accounts number from company.
this.srvCompany.currentAccountsNumber.subscribe(accountsNumber => {
console.log(accountsNumber);
if (accountsNumber.length > 0) {
this.srvInvoice.getInvoice(accountsNumber).then(data => this.invoice = data.json());
}
});
}
//getInvoice(id: any) {
// this.srvInvoice.getInvoice(id).then(data => this.invoice = data.json());
//}
}
company.component.ts (the trigerring "parent")
import { Component, Inject, OnInit, Input } from '#angular/core';
import { Headers, Http, Response } from '#angular/http';
import { SrvCompany } from './company.service';
#Component({
selector: 'company',
templateUrl: 'tsScripts/company/company.html',
providers: [SrvCompany]
})
export class CompanyComponent implements OnInit {
societes: any[];
soc: Response[]; // debug purpose
selectedSociete: any;
ville: any;
ref: any;
cp: any;
accountNumber: any[];
constructor(private srvSociete: SrvCompany)
{
}
ngOnInit(): void {
this.getSocietes();
}
getSocietes(): void {
this.srvSociete.getSociete()
.then(data => this.societes = data.json())
.then(data => this.selectItem(this.societes[0].Id));
}
selectItem(value: any) {
this.selectedSociete = this.societes.filter((item: any) => item.Id === value)[0];
this.cp = this.selectedSociete.CodePostal;
this.ville = this.selectedSociete.Ville;
this.ref = this.selectedSociete.Id;
this.accountNumber = this.selectedSociete.Accounts;
console.log(this.accountNumber);
this.srvSociete.changeMessage(this.accountNumber);
}
}
This is a case where you want to use a shared service, as your components are structured as siblings and grandchildren. Here's an example from a video I created a video about sharing data between components that solves this exact problem.
Start by creating a BehaviorSubject in the service
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class DataService {
private messageSource = new BehaviorSubject("default message");
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
Then inject this service into each component and subscribe to the observable.
import { Component, OnInit } from '#angular/core';
import { DataService } from "../data.service";
#Component({
selector: 'app-parent',
template: `
{{message}}
`,
styleUrls: ['./sibling.component.css']
})
export class ParentComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
}
You can change the value from either component and the value will be updated, even if you don't have the parent/child relationship.
import { Component, OnInit } from '#angular/core';
import { DataService } from "../data.service";
#Component({
selector: 'app-sibling',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {
message:string;
constructor(private data: DataService) { }
ngOnInit() {
this.data.currentMessage.subscribe(message => this.message = message)
}
newMessage() {
this.data.changeMessage("Hello from Sibling")
}
}
if component are not related than you need use Service
https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
There are two solutions for this.
This can be done through shared service by using observable's.
You can use ngrx/store for this. This is similar to Redux arch. You will be getting data from state.
Here is the simplest example of sharing data between two independent components, using event emitter and service
https://stackoverflow.com/a/44858648/8300620
When you mention non related components, I'm gonna assume that they don't have any parent component. If assumption isn't correct, feel free to read another of my answers where both cases are addressed.
So, as there's no common parent, we can use an injectable service. In this case, simply inject the service in the components and subscribe to its events.
(Just like the next image shows - taken from here - except that we'll inject the service in two Components)
The documentation explains it quite well how to Create and register an injectable service.
Related
I want to send the value from one component to another, they are not related so all solutions are saying that I must use shared service to do that. But these services are using templates (if I'm right). Is there a way to do this sharing without services?
I want to send the BMI value from homepage.component.ts to result.component.ts.
homepage.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css']
})
export class HomepageComponent implements OnInit {
constructor() { }
myHeight!:number;
myWeight!:number;
bmi!:number;
ngOnInit(): void {
}
onGenerate( height:string,width:string){
this.myHeight = +height;
this.myHeight=Math.pow(this.myHeight/100,2);
this.myWeight = +width;
this.bmi=this.myWeight/this.myHeight
console.log(this.bmi); //this is the calculated value to send
}
}
result.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-result',
templateUrl: './result.component.html',
styleUrls: ['./result.component.css']
})
export class ResultComponent implements OnInit {
constructor() { }
//I want to get the bmi here
ngOnInit(): void {
}
}
There are Two ways to communicate between unrelated components in angular:
1 - Through services, you have to understand where to inject it, in your case I think it should be injected in root, so try this with your service ( follow this tutorial to implement your service, just add my code instead of theirs )
#Injectable({
providedIn: 'root',
})
2 - Through a store ( a lot of boilerplate coding, to use if you have complexe states to keep synchronized through the whole app, by the way the store is basically a service )
If your components are not related then you can create a shared service between them. Then, you need to use dependency injection to communicate between these components. So, there is a great Angular tutorial which describes how to do it.
The service code would look like this:
#Injectable()
export class FooService {
constructor( ) { }
private yourData;
setData(data){
this.yourData = data;
}
getData(){
let temp = this.yourData;
this.clearData();
return temp;
}
}
and sender component:
import { Router } from '#angular/router';
import { FooService} from './services/foo.service';
export class SenderComponent implements OnInit {
constructor(
private fooService: FooService,
private router:Router) {}
somefunction(data){
this.fooService.setData(data);
this.router.navigateByUrl('/reciever');//as per router
}
}
and subscriber:
import { Router } from '#angular/router';
import { TransfereService } from './services/transfer.service';
export class RecieverComponent implements OnInit {
data;
constructor(
private fooService: FooService){
}
ngOnInit() {
data = this.transfereService.getData();
console.log(`data: `, data)
}
}
Solution: To pass the data from one component to another we can store it in a session storage or a local storage and then access it in other components from that storage. Here I have provided a sample code using local storage for your reference.
homepage.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-homepage',
templateUrl: './homepage.component.html',
styleUrls: ['./homepage.component.css']
})
export class HomepageComponent implements OnInit {
constructor() { }
myHeight!:number;
myWeight!:number;
data:string='';
bmi!:number;
ngOnInit(): void {
}
onGenerate( height:string,width:string){
this.myHeight = +height;
this.myHeight=Math.pow(this.myHeight/100,2);
this.myWeight = +width;
this.bmi=this.myWeight/this.myHeight;
this.data=localStorage.setItem('bmi',this.bmi);
console.log(this.bmi); //this is the calculated value to send
}
}
resultcomponent.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-result',
templateUrl: './result.component.html',
styleUrls: ['./result.component.css']
})
export class ResultComponent implements OnInit {
data:any;
constructor() { this.data=localstorage.getItem('bmi')}
//Access the bmi using the data variable here
ngOnInit(): void {
}
}
I'm still new to Angular and learning Angular 8 currently.
I'm trying to create a simple API communication Service to load the data needed for display. I have a main Component with a sub-Component and both need to fetch data to load.
I've tried following several tutorials but my common issue is that the Component loading is happening before the API HTTP request is returned, leading to undefined data.
My current API Service uses HttpClient to communicate with the API
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) {}
getUserFeed(id: number): Observable<Post[]> {
return this.http
.get<Post[]>(`${API_URL}/feed`)
.pipe(
retry(3),
catchError(this.handleError)
);
}
getProfile(id: number): Observable<Profile> {
return this.http
.get<Profile>(`${API_URL}/profile/${id}`)
.pipe(
retry(3),
catchError(this.handleError)
);
}
handleError(error: any) {
let errorMessage: string;
// Set error message
(error.error instanceof ErrorEvent) ?
errorMessage = error.error.message :
errorMessage = `Error Code: ${error.code}\nMessage: ${error.message}`;
console.log(errorMessage);
return throwError(errorMessage);
}
}
The API should be returning an array of Posts I've defined.
I call this in my component as
import { Component, OnInit } from '#angular/core';
import { UserService } from '../user/user.service';
import { ApiService } from '../api/api.service';
import { User } from '../user';
import { Post } from '../Post';
#Component({
selector: 'app-feed',
templateUrl: './feed.component.html',
styleUrls: ['./feed.component.css'],
})
export class FeedComponent implements OnInit {
posts: Post[] = [];
user: User;
post: Post;
constructor(private userService: UserService) {
this.user = this.userService.user;
}
public ngOnInit() {
this.userService.getUserFeed(this.user.id).subscribe((feed) => {
this.posts = feed;
console.log(this.posts);
});
}
}
My Component HTML should loop through these posts and pass the post to the sub-Components I have
<div *ngIf="posts.length">
<mat-list *ngFor="let post of posts">
<!-- Post Display -->
<app-post-display [post]=post></app-post-display>
<!-- Post Interaction Row -->
<app-post-interaction-bar [post]=post></app-post-interaction-bar>
<!-- Comment Preview -->
<app-comment-preview [post]=post></app-comment-preview>
<mat-divider></mat-divider>
</mat-list>
</div>
So far it seems to be picking up the posts for the main component as expected. The issue is in the sub-Component app-post-display which performs a similar action getting the post author from the post.authorId property.
I've declared an author and I've placed the code to fetch the author data in ngOnInit but I consistently get ERROR TypeError: Cannot read property 'id' of undefined in the console, no matter what I try it seems that the Component is trying to display before the author is fetched.
What do I need to adjust to have the author data fetched before the Component display is loaded
import { Component, Input, OnInit } from '#angular/core';
import { UserService } from '../user/user.service';
import { User } from '../user';
import { Post } from '../post';
import { Profile } from '../profile';
import { ApiService } from '../api/api.service';
#Component({
selector: 'app-post-display',
templateUrl: './post-display.component.html',
styleUrls: ['./post-display.component.css'],
})
export class PostDisplayComponent implements OnInit {
#Input() post: Post;
user: User;
author: Profile;
constructor(private userService: UserService, private backend: BackendService) {
this.user = this.userService.user;
}
ngOnInit() {
this.backend.getProfile(this.post.authorId).subscribe((profile) => {
this.author = profile;
console.log(this.author);
});
}
}
ngOnInit of the Child Component will run only once. Also, you can't expect it to get the post defined initially.
To fix it, you should move your call to ngOnChanges and check if post is defined first. Here, give this a try:
import { Component, Input, OnChanges } from '#angular/core';
import { UserService } from '../user/user.service';
import { User } from '../user';
import { Post } from '../post';
import { Profile } from '../profile';
import { ApiService } from '../api/api.service';
#Component({
selector: 'app-post-display',
templateUrl: './post-display.component.html',
styleUrls: ['./post-display.component.css'],
})
export class PostDisplayComponent implements OnChanges {
#Input() post: Post;
user: User;
author: Profile;
constructor(
private userService: UserService,
private backend: BackendService
) {
this.user = this.userService.user;
}
ngOnChanges() {
if (this.post) {
this.backend.getProfile(this.post.authorId).subscribe((profile) => {
this.author = profile;
console.log(this.author);
});
}
}
}
Alternatively, you can do that in your Parent Component:
<div *ngIf="posts">
<mat-list *ngFor="let post of posts">
<!-- Post Display -->
<app-post-display [post]=post></app-post-display>
<!-- Post Interaction Row -->
<app-post-interaction-bar [post]=post></app-post-interaction-bar>
<!-- Comment Preview -->
<app-comment-preview [post]=post></app-comment-preview>
<mat-divider></mat-divider>
</mat-list>
</div>
Just make sure you're not initializing the posts with an empty array initially though.
The best answer I found for my problem was actually using a resolver before the page is directed to (https://angular.io/api/router/Resolve).
This allowed the data to be loaded before the page was fully rendered, hence no errors.
I wanted to know how I do to use an array in two angular components without the need to make two http.get requests.
My service.
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { environment } from '../../../environments/environment';
#Injectable()
export class CategoryService {
constructor(
private http: Http
) {
}
getAll(): Promise<any> {
return this.http.get(`${environment.apiUrl}/categories`)
.toPromise()
.then(response => response.json());
}
}
First component
Here I am making the first requisition.
import { Component, OnInit } from '#angular/core';
import { PostService } from './../core/service/post.service';
import { CategoryService } from './../core/service/category.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
categories = [];
constructor(
private postService: PostService,
private categoryService: CategoryService
) { }
ngOnInit() {
this.getAllCategories();
}
getAllCategories() {
return this.categoryService.getAll()
.then(categories => {
this.categories = categories;
})
.catch(error => {
throw error;
});
}
}
Second component
Here I am making the second requisition.
import { Component, OnInit } from '#angular/core';
import { CategoryService } from './../core/service/category.service';
#Component({
selector: 'app-footer',
templateUrl: './footer.component.html',
styleUrls: ['./footer.component.css']
})
export class FooterComponent implements OnInit {
categories = [];
constructor(
private categoryService: CategoryService
) { }
ngOnInit() {
this.getAllCategories();
}
getAllCategories() {
return this.categoryService.getAll()
.then(categories => {
this.categories = categories;
})
.catch(error => {
throw error;
});
}
}
Could I create a public array in service? or it would be bad practice
A better approach would be to leverage “caching”.
1) To enhance your architecture, create one http-wrapper.service.ts, which wraps all http methods and have one property here to either read from cache or make an actual http get call. Donot cache post etc request.
2) Moreover create an http-cache.interceptor.ts, where in you can write logic to make an actual http get call or reutrn result from cache
These are the two best approaches which will not only solve your problem, but also enhance your architecture and handle all generic requests
Cheers (y)
Update 1
After I read Alexanders suggestions, I updated the code and got no error back. But Angular doesn't do a request to the server anymore, which make me curious. And also the pageTitle does not update.
appointmentDetail.component.html
{{appointmentDetail.time}}
appointmentDetail.component.ts
import { Component, OnInit, OnDestroy, Injectable } from '#angular/core';
import { ActivatedRoute, ParamMap } from '#angular/router';
import { Title } from '#angular/platform-browser';
import { APIService } from './../../../api.service';
import { Observable } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
#Component({
selector: 'app-appointmentdetail',
templateUrl: './appointmentDetail.component.html',
styleUrls: ['./appointmentDetail.component.scss']
})
export class AppointmentDetailComponent implements OnInit {
id: any;
appointmentDetail$: Observable<Object>; // I'd really create an interface for appointment or whatever instead of object or any
pageTitle = 'Some Default Title Maybe';
constructor(
private route: ActivatedRoute,
private title: Title,
private apiService: APIService
) {}
ngOnInit() {
this.appointmentDetail$ = this.route.paramMap.pipe(
tap((params: ParamMap) => {
this.id = params.get('id');
// Or this.id = +params.get('id'); to coerce to number maybe
this.pageTitle = 'Termin' + this.id;
this.title.setTitle(this.pageTitle);
}),
switchMap(() => this.apiService.getAppointmentDetailsById(this.id))
);
}
public getData() {
this.apiService
.getAppointmentDetailsById(this.id)
.subscribe((data: Observable<Object>) => {
this.appointmentDetail$ = data;
console.log(data);
});
}
}
api.service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class APIService {
API_URL = 'http://localhost:5000';
constructor(private httpClient: HttpClient) {}
getAppointments() {
return this.httpClient.get(`${this.API_URL}/appointments/`);
}
getAppointmentDetailsById(id) {
return this.httpClient.get(`${this.API_URL}/appointments/${id}`);
}
getAppointmentsByUser(email) {
return this.httpClient.get(`${this.API_URL}/user/${email}/appointments`);
}
getCertificatesByUser(email) {
return this.httpClient.get(`${this.API_URL}/user/${email}/certificates`);
}
}
As you can see, I want to grab that parameter id from the router parameters and want to pass it into my API call, which will do a Angular HTTP request. Hope I'm right, haha.
Original Question
Currently, I ran into a nasty problem. The thing is, I want to read the params, which are given to me by ActivatedRouter and the Angular OnInit function. I subscribe them params and log them in the console. Until here, everything is working fine. But I want to access "this.id" outside from my OnInit function, so I can use it on pageTitle for example.
But, this.id is undefined. So the page title is Termineundefined.
Source code:
import { Component, OnInit, OnDestroy, Injectable } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { Title } from '#angular/platform-browser';
import { APIService } from './../../api.service';
#Component({
selector: 'app-appointment-details',
templateUrl: './appointment-details.component.html',
styleUrls: ['./appointment-details.component.scss']
})
#Injectable()
export class AppointmentDetailsComponent implements OnInit, OnDestroy {
private routeSub: any;
id: any;
private appointmentDetail: Array<object> = [];
constructor(
private route: ActivatedRoute,
private title: Title,
private apiService: APIService
) {}
pageTitle = 'Termin' + this.id;
ngOnInit() {
this.title.setTitle(this.pageTitle);
this.getData();
this.routeSub = this.route.params.subscribe(params => {
console.log(params);
this.id = params['id'];
});
}
ngOnDestroy() {
this.routeSub.unsubscribe();
}
public getData() {
this.apiService
.getAppointmentDetailsById(this.id)
.subscribe((data: Array<object>) => {
this.appointmentDetail = data;
console.log(data);
});
}
}
The issue here really comes down to async availability of route params and observable streams. You simply cannot use the value until it has resolved for all practical purposes. You can use RxJS operators such as switchMap and tap in line with the official Routing & Navigation documentation to ensure route param id is available prior to use. tap can be used to introduce side effects such as setting class id property from route params and/or setting title. You could even create a class property of an Observable<YourObject[]> and utilize Angular Async Pipe to avoid subscribing and unsubscribing to display the data.
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { Title } from '#angular/platform-browser';
import { APIService, MyFancyInterface } from './../../api.service';
import { Observable } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';
#Component({
selector: 'app-appointment-details',
templateUrl: './appointment-details.component.html',
styleUrls: ['./appointment-details.component.scss']
})
export class AppointmentDetailsComponent implements OnInit {
id: any;
appointmentDetail$: Observable<MyFancyInterface>;
appointmentDetail: MyFancyInterface;
pageTitle = 'Some Default Title Maybe';
constructor(
private route: ActivatedRoute,
private title: Title,
private apiService: APIService
) {}
ngOnInit() {
this.appointmentDetail$ = this.route.paramMap.pipe(
tap((params: ParamMap) => {
this.id = params.get('id')
// Or this.id = +params.get('id'); to coerce to type number maybe
this.pageTitle = 'Termin' + this.id;
this.title.setTitle(this.pageTitle);
}),
switchMap(() => this.apiService.getAppointmentDetailsById(this.id))
);
/* Or
this.route.paramMap.pipe(
tap((params: ParamMap) => {
this.id = params.get('id')
// Or this.id = +params.get('id'); to coerce to type number maybe
this.pageTitle = 'Termin' + this.id;
this.title.setTitle(this.pageTitle);
}),
switchMap(() => this.apiService.getAppointmentDetailsById(this.id))
).subscribe((data: MyFancyInterface) => {
this.appointmentDetail = data;
});
*/
}
}
Template:
<div>{{(appointmentDetail | async)?.id}}</div>
I'd recommend to create an interface to represent your data model and type the return of your api service method:
import { Observable } from 'rxjs';
// maybe put this into another file
export interface MyFancyInterface {
id: number;
someProperty: string;
...
}
export class APIService {
...
getAppointmentDetailsById(id): Observable<MyFancyInterface> {
return this.httpClient.get<MyFancyInterface>(`${this.API_URL}/appointments/${id}`);
}
...
}
If you really must, you can save the observable as you do now for the route params and subscribe as needed in the various parts of the class, but this demonstrated way you almost absolutely know that route param id will be available for use and can explicitly set the things you need to set.
I'd also remove #Injectable() as there is no reason to have it here with a #Component() decorator.
Note* the async pipe operator in this example ensures the Http call is executed. Otherwise a subscribe() is needed (search SO for Angular http not executing to see similar issues)
Hopefully that helps!
Instead of
id: any;
You could try using a getter, like so
public get id(): any {
this.route.params.subscribe(params => {
return params['id'];
}
}
In your template, just
{{ id }}
I'm having trouble implementing a service that loads the data (gyms array) once, then allows all other components to use it, without making other HTTP requests.
My application works fine if the user started at the title page and loaded all the data, but when I go to a specific detail page (.../gym/1) and reload the page, the object isn't in the service array yet. How can I make the component that tries to access the service array wait until the data is loaded? More specifically, how can I delay the call of gymService.getGym(1) in the GymComponent until the getAllGymsFromBackEnd() function is done populating the array?
I've read about resolvers but my tinkering led me nowhere.
Any help would be appreciated.
This is the code I was working on:
Service:
import {Injectable} from "#angular/core";
import {Gym} from "../objects/gym";
import {BaseService} from "./base.service";
import {Http, Response} from "#angular/http";
import {HttpConstants} from "../utility/http.constants";
#Injectable()
export class GymService extends BaseService {
private gyms: Gym[] = [];
constructor(protected http: Http, protected httpConstants: HttpConstants) {
super(http, httpConstants);
this.getAllGymsFromBackEnd();
}
getAllGymsFromBackEnd() {
return super.get(this.httpConstants.gymsUrl).subscribe(
(data: Response) => {
for (let gymObject of data['gyms']) {
this.gyms.push(<Gym>gymObject);
}
}
);
}
getGyms() {
return this.gyms;
}
getGym(id: number) {
return this.gyms.find(
gym => gym.id === id
)
}
}
Component:
import {Component, OnDestroy, AfterViewInit, OnInit} from "#angular/core";
import {ActivatedRoute} from "#angular/router";
import {Subscription} from "rxjs";
import {Gym} from "../../objects/gym";
import {GymService} from "../../services/gym.service";
declare var $:any;
#Component({
selector: 'app-gym',
templateUrl: './gym.component.html',
styleUrls: ['./gym.component.css']
})
export class GymComponent implements OnInit, OnDestroy, AfterViewInit {
private subscription: Subscription;
private gym: Gym;
constructor(private activatedRoute: ActivatedRoute,
private gymService: GymService
) {}
ngOnInit(): void {
this.subscription = this.activatedRoute.params.subscribe(
(param: any) => {
this.gym = this.gymService.getGym(parseInt(param['id']));
}
);
}
ngAfterViewInit(): void {
$( document ).ready(function() {
$('.carousel').carousel();
});
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
}
You can use Resolver as well. Check it here https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html or use Observable. So the private gym: Gym; will become private gym$:Observable<Gym>;, and in your template, use async pipe to get the data.