Angular 2 Sibling Component Communication

前端 未结 12 1288
深忆病人
深忆病人 2020-11-22 06:31

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

相关标签:
12条回答
  • 2020-11-22 07:21

    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.

    0 讨论(0)
  • 2020-11-22 07:22

    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.

    0 讨论(0)
  • 2020-11-22 07:25

    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/

    0 讨论(0)
  • 2020-11-22 07:26

    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

    0 讨论(0)
  • 2020-11-22 07:26

    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;
    }
    
    0 讨论(0)
  • 2020-11-22 07:28

    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/

    0 讨论(0)
提交回复
热议问题