Edon
Edon

Reputation: 1216

Angular 2 shared service to pass data to component-to-component

I am trying to pass the string value of this.title from my LandingPage.component to my ResultPage.component.

I retrieve the list.show value, and send it to my TitleService in like so in my:

landingpage.component.html

<ol>
  <li (click)="selectShow(list.show)" [routerLink]="['/details', list.id]" *ngFor="let list of shows">{{list.show}}
  </li>
</ol>

landingpage.component.ts

import { TitleService } from '../../services/title.service';

constructor(private TitleService: TitleService) {}

selectShow(show) {
  this.TitleService.fetchTitle(show)
}

The above sends the list.show value to my:

title.service.ts

// this gives us the name of the clicked show, which we send to TitleResolver
@Injectable()
export class TitleService {
  fetchTitle(title) {
    console.log("title is " + title); // this outputs correctly
    return title;
  }
}

And here is how I manage the routing in my:

app-routing.module.ts

import { TitleService } from './services/title.service';

const routes: Routes = [
  { path: '', component: LandingPage },
  {
    path: 'details/:id', component: ResultPage
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [TitleService]
})

My question

Once I receive the title.show value in my service component, I'm unsure how to then send it to my receiving component (resultpage.component)

How can I send my title value from my service to my ResultPage.component?

Upvotes: 1

Views: 2915

Answers (3)

Dan
Dan

Reputation: 1355

Separation of concerns... Your landing page is used to select the list item and navigate to the result page. Let it do just that and only that. Let the ResultPage.component do the rest. Note: Other answers recommend storing the value of the last title in the TitleService. It's not a good idea to store state in a service. Then TitleService cannot be used as a generic way to get any title separate from your current navigation, without side effects.

Remove (click) event. Add 'show' as a QueryParam.

landingpage.component.html

<li [routerLink]="['/details', list.id]" 
    [queryParams]="{show: list.show}" 
     *ngFor="let list of shows">
     {{list.show}}
</li>

Subscribe to router params and queryparams to get the id and show.

resultpage.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { TitleService } from '../../services/title.service';

@Component({
  ...
})
export class ResultPageComponent implements OnInit, OnDestroy {

 itemId: string;
 show: string;
 subParams: any;       // infinite Observable to be unsubscribed
 subQueryParams: any;  // infinite Observable to be unsubscribed

 constructor(
          ... 
          private TitleService: TitleService,
          protected route: ActivatedRoute,
          protected router: Router,
          ...
 ) {}

 ngOnInit() {
   this.subParams = this.route.params.subscribe(this.onParams);
   this.subQueryParams = this.route.queryParams(this.onQueryParams);
 }

 ngOnDestroy() {
   // Delete active subscribes on destroy
   this.subParams.unsubscribe();  
   this.subQueryParams.unsubscribe();  
 }

 onParams = (params: any) => {
   this.itemId = params['id'];
 }

 onQueryParams = (data: any) => {
  this.show = data.show;
  if(this.show) {
    this.TitleService.fetchTitle(this.show)
  }
 }

Upvotes: 0

Nehal
Nehal

Reputation: 13307

In title.service.ts you can declare a variable called title and have setter and getter:

title: string ="";

// replace fetchTitle with setTitle 
// remember to change it in the component too
setTitle(title) {
    this.title = title;
  }

getTitle() {
    return this.title;
  }

Then, when ResultPage.component is initialized, call getTitle() from TitleService and set the result to a variable declared in the component.

Here's an example of sharing data via shared services.

Upvotes: 2

DeborahK
DeborahK

Reputation: 60518

Make the title a public property of the service like this:

// this gives us the name of the clicked show, which we send to TitleResolver
@Injectable()
export class TitleService {
  selectedTitle: string;

  fetchTitle(title) {
    console.log("title is " + title); // this outputs correctly
    this.selectedTitle = title;
    return title;   // No need to return it.
  }
}

Then any other component can inject this service and access this.titleService.selectedTitle

Upvotes: 3

Related Questions