I have a ListComponent. When an item is clicked in ListComponent, the details of that item should be shown in DetailComponent. Both are on the screen at the same time, so
Shared service is a good solution for this issue. If you want to store some activity information too, you can add Shared Service to your main modules (app.module) provider list.
@NgModule({
imports: [
...
],
bootstrap: [
AppComponent
],
declarations: [
AppComponent,
],
providers: [
SharedService,
...
]
});
Then you can directly provide it to your components,
constructor(private sharedService: SharedService)
With Shared Service you can either use functions or you can create a Subject to update multiple places at once.
@Injectable()
export class SharedService {
public clickedItemInformation: Subject<string> = new Subject();
}
In your list component you can publish clicked item information,
this.sharedService.clikedItemInformation.next("something");
and then you can fetch this information at your detail component:
this.sharedService.clikedItemInformation.subscribe((information) => {
// do something
});
Obviously, the data that list component shares can be anything. Hope this helps.
This is not what you exactly want but for sure will help you out
I'm surprised there's not more information out there about component communication <=> consider this tutorial by angualr2
For sibling components communication, I'd suggest to go with sharedService
. There are also other options available though.
import {Component,bind} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from 'angular2/http';
import {NameService} from 'src/nameService';
import {TheContent} from 'src/content';
import {Navbar} from 'src/nav';
@Component({
selector: 'app',
directives: [TheContent,Navbar],
providers: [NameService],
template: '<navbar></navbar><thecontent></thecontent>'
})
export class App {
constructor() {
console.log('App started');
}
}
bootstrap(App,[]);
Please refer to link at top for more code.
Edit: This is a very small demo. You have already mention that you have already tried with sharedService
. So please consider this tutorial by angualr2 for more information.
Here is simple practical explanation:Simply explained here
In call.service.ts
import { Observable } from 'rxjs';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class CallService {
private subject = new Subject<any>();
sendClickCall(message: string) {
this.subject.next({ text: message });
}
getClickCall(): Observable<any> {
return this.subject.asObservable();
}
}
Component from where you want to call observable to inform another component that button is clicked
import { CallService } from "../../../services/call.service";
export class MarketplaceComponent implements OnInit, OnDestroy {
constructor(public Util: CallService) {
}
buttonClickedToCallObservable() {
this.Util.sendClickCall('Sending message to another comp that button is clicked');
}
}
Component where you want to perform action on button clicked on another component
import { Subscription } from 'rxjs/Subscription';
import { CallService } from "../../../services/call.service";
ngOnInit() {
this.subscription = this.Util.getClickCall().subscribe(message => {
this.message = message;
console.log('---button clicked at another component---');
//call you action which need to execute in this component on button clicked
});
}
import { Subscription } from 'rxjs/Subscription';
import { CallService } from "../../../services/call.service";
ngOnInit() {
this.subscription = this.Util.getClickCall().subscribe(message => {
this.message = message;
console.log('---button clicked at another component---');
//call you action which need to execute in this component on button clicked
});
}
My understanding clear on components communication by reading this: http://musttoknow.com/angular-4-angular-5-communicate-two-components-using-observable-subject/
In case of 2 different components (not nested components, parent\child\grandchild ) I suggest you this:
MissionService:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class MissionService {
// Observable string sources
private missionAnnouncedSource = new Subject<string>();
private missionConfirmedSource = new Subject<string>();
// Observable string streams
missionAnnounced$ = this.missionAnnouncedSource.asObservable();
missionConfirmed$ = this.missionConfirmedSource.asObservable();
// Service message commands
announceMission(mission: string) {
this.missionAnnouncedSource.next(mission);
}
confirmMission(astronaut: string) {
this.missionConfirmedSource.next(astronaut);
}
}
AstronautComponent:
import { Component, Input, OnDestroy } from '@angular/core';
import { MissionService } from './mission.service';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'my-astronaut',
template: `
<p>
{{astronaut}}: <strong>{{mission}}</strong>
<button
(click)="confirm()"
[disabled]="!announced || confirmed">
Confirm
</button>
</p>
`
})
export class AstronautComponent implements OnDestroy {
@Input() astronaut: string;
mission = '<no mission announced>';
confirmed = false;
announced = false;
subscription: Subscription;
constructor(private missionService: MissionService) {
this.subscription = missionService.missionAnnounced$.subscribe(
mission => {
this.mission = mission;
this.announced = true;
this.confirmed = false;
});
}
confirm() {
this.confirmed = true;
this.missionService.confirmMission(this.astronaut);
}
ngOnDestroy() {
// prevent memory leak when component destroyed
this.subscription.unsubscribe();
}
}
Source: Parent and children communicate via a service
I also like to do the communication between 2 siblings via a parent component via input and output. it handles OnPush change notification better than using a common service. Or just use NgRx Store.
Example.
@Component({
selector: 'parent',
template: `<div><notes-grid
[Notes]="(NotesList$ | async)"
(selectedNote)="ReceiveSelectedNote($event)"
</notes-grid>
<note-edit
[gridSelectedNote]="(SelectedNote$ | async)"
</note-edit></div>`,
styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
// create empty observable
NotesList$: Observable<Note[]> = of<Note[]>([]);
SelectedNote$: Observable<Note> = of<Note>();
//passed from note-grid for selected note to edit.
ReceiveSelectedNote(selectedNote: Note) {
if (selectedNote !== null) {
// change value direct subscribers or async pipe subscribers will get new value.
this.SelectedNote$ = of<Note>(selectedNote);
}
}
//used in subscribe next() to http call response. Left out all that code for brevity. This just shows how observable is populated.
onNextData(n: Note[]): void {
// Assign to Obeservable direct subscribers or async pipe subscribers will get new value.
this.NotesList$ = of<Note[]>(n.NoteList); //json from server
}
}
//child 1 sibling
@Component({
selector: 'note-edit',
templateUrl: './note-edit.component.html', // just a textarea for noteText and submit and cancel buttons.
styleUrls: ['./note-edit.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NoteEditComponent implements OnChanges {
@Input() gridSelectedNote: Note;
constructor() {
}
// used to capture @Input changes for new gridSelectedNote input
ngOnChanges(changes: SimpleChanges) {
if (changes.gridSelectedNote && changes.gridSelectedNote.currentValue !== null) {
this.noteText = changes.gridSelectedNote.currentValue.noteText;
this.noteCreateDtm = changes.gridSelectedNote.currentValue.noteCreateDtm;
this.noteAuthorName = changes.gridSelectedNote.currentValue.noteAuthorName;
}
}
}
//child 2 sibling
@Component({
selector: 'notes-grid',
templateUrl: './notes-grid.component.html', //just an html table with notetext, author, date
styleUrls: ['./notes-grid.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NotesGridComponent {
// the not currently selected fromt eh grid.
CurrentSelectedNoteData: Note;
// list for grid
@Input() Notes: Note[];
// selected note of grid sent out to the parent to send to sibling.
@Output() readonly selectedNote: EventEmitter<Note> = new EventEmitter<Note>();
constructor() {
}
// use when you need to send out the selected note to note-edit via parent using output-> input .
EmitSelectedNote(){
this.selectedNote.emit(this.CurrentSelectedNoteData);
}
}
// here just so you can see what it looks like.
export interface Note {
noteText: string;
noteCreateDtm: string;
noteAuthorName: string;
}
There is a discussion about it here.
https://github.com/angular/angular.io/issues/2663
Alex J's answer is good but it no longer works with current Angular 4 as of July, 2017.
And this plunker link would demonstrate how to communicate between siblings using shared service and observable.
https://embed.plnkr.co/P8xCEwSKgcOg07pwDrlO/