Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to communicate parent component interaction through child route component? (Angular2)

In the root component of the route configuration I have a button. When I click this button, I would like to trigger an event inside the activated child route.

I have been struggling with this for a while now, and the only thing that seems promising is using a bi-directional service (link to angular docs). However, I'm not sure how to get it working.

Here is a plunk to demonstrate:

https://plnkr.co/edit/7zDTTTlABWD2GFo01jaz?p=preview

I've set up a simple route configuration which automatically redirects to the TestComponent. When I click on the 'click' button at the route app level, I would like to be able to trigger the clickDetected() function inside TestComponent.

Hope everything is clear - any advice is appreciated!

Code below;


app.component

@Component({
  selector: 'my-app',
  template: `
    <input type="button" (click)="onClick('hello')" value="click" />
    <router-outlet></router-outlet>
  `,
})
export class AppComponent {
  constructor(private testService: TestService) {
  }

  onClick(v){
    this.testService.declareClick(v)
  }
}

test.service

@Injectable()
export class TestService {

  private clickedSource = new Subject<string>();

  clicked$ = this.clickedSource.asObservable();

  declareClick(value: string) {
    console.log(value)
    return this.clickedSource.next(value);
  }

}

test.component

@Component({
  selector: 'my-test',
  template: `
    <div>
      <h1>Test Component</h1>
    </div>
  `,
})
export class TestComponent implements OnInit {

  public clicked?: any

  constructor(private testService: TestService) {
  }

  clickDetected(){
   console.log("parent clicked")
  }

  ngOnInit(){
    this.testService.declareClick()
/*      .subscribe((v) => {
        this.clicked? = v;
        console.log(v)
      })*/
  }

}
like image 232
lolio Avatar asked Jan 27 '17 12:01

lolio


People also ask

How do you communicate between parent and child components?

@Input() and @Output() give a child component a way to communicate with its parent component. @Input() lets a parent component update data in the child component. Conversely, @Output() lets the child send data to a parent component.

How do you access the parent component function in a child component?

To call a parent component method from the child component, we need to pass the changeName() method as a prop to the child component and access it as a props data inside the child component.


2 Answers

EDIT -- DO NOT DO THIS --

Thanks to @echonax, I learned that is actually an example of what you should NOT do. I came to actually help people and I ended up learning something. Please, refer to the angular2 doc on why you should NOT do this.

END EDIT

You can also do this using a Shared Module. You make a module that provide the test service and import both in AppModule and your routed module. You can then provide the same instance of the service to both component. I made you a plunkr from your code that show how it works.

If you want more information on SharedModule, check Angular2 doc. https://angular.io/docs/ts/latest/guide/ngmodule.html#!#shared-module

Edited your question plunkr. https://plnkr.co/edit/SU8AT4


Shared Module

import { NgModule } from '@angular/core';
import { TestService } from './test.service';

@NgModule({
  imports: [],
  declarations: [],
  providers: [
    TestService
  ],
  exports: [ ]
})
export class SharedModule { }

New AppModule

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { TestComponent } from './test.component';
import { SharedModule } from './shared.module';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  imports: [
    BrowserModule,
    AppRoutingModule,
    SharedModule
  ],
  declarations: [
    AppComponent,
    TestComponent
  ],
  providers: [ ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

New AppRoutingModule

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { TestComponent }  from './test.component';
import { SharedModule } from './shared.module';

const appRoutes: Routes = [
  { path: '',   redirectTo: 'test', pathMatch: 'full' },
  { path: 'test',  component: TestComponent },
];

@NgModule({
  imports: [
    RouterModule.forRoot(appRoutes),
    SharedModule
  ],
  exports: [ RouterModule ],
  providers: []
})
export class AppRoutingModule { }
like image 24
Simon Dufour Avatar answered Oct 10 '22 05:10

Simon Dufour


You just need to .subscribe() to the Observable that is receiving the .next() events:

this.testService.clickedSource.subscribe((val)=>{
  console.log(2, val);
});

Fixed Plunker: https://plnkr.co/edit/aPR6KvuOi2tgQXLgokHi?p=preview

like image 197
eko Avatar answered Oct 10 '22 05:10

eko