Home @Output communication between child and parent. Angular 2(5)
Reply: 2

@Output communication between child and parent. Angular 2(5)

Cheekumz
1#
Cheekumz Published in 2017-11-14 17:34:19Z

I'm trying to learn angular 2 and am trying to set a variable in a parent component with data from my child components. Basically I have a subheader in my parent view and I want the title and some HTML to change based on what child is loaded.

Parent component:

import { Component, OnInit, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class ParentComponent {
  childDetails: {title: String, helperBar: String};

  onChildLoaded(childData: {
    childTitle: string,
    childHelperBar: string
  }) {
    this.childDetails ={
      title: childData.childTitle,
      helperBar: childData.childHelperBar
    };
    console.log (childDetails);
  }
}

Child Component :

import { Component, OnInit, ViewEncapsulation, Output, EventEmitter } 
from '@angular/core';

@Component({
  selector: 'app-first-child',
  templateUrl: './first-child.component.html',
  styleUrls: ['./first-child.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class FirstChildComponent implements OnInit {
  @Output() childLoaded = new EventEmitter<{childTitle: string, 
childHelperBar: string}>();

  constructor() { }

  ngOnInit() {
    this.childLoaded.emit({
      childTitle: 'Dashboard',
      childHelperBar: '<div class="test"><button>Dash Button</button>
</div>'
    });
  }

}

And finally my parent HTML:

<div class="subheader">
  <h1>{{ childDetails.title }}</h1>
  {{ childDetails.helperBar }}
</div>
<nav class="sidebar">

</nav>

<main role="main" class="">
  <router-outlet (childLoaded)="onChildLoaded($event)"></router-outlet>
</main>

For the life of me I can't get this approach to work and can't pinpoint where I'm going wrong. I could always just put the subheader in my children but I dont like the idea of repeating the code so many times and it will make my layout a bit harder to achieve.

Veena K. Suresh
2#
Veena K. Suresh Reply to 2017-11-15 07:11:50Z

The best way is making use of the service and observable so that whenever the child component changes, the new data will get immediately reflected in the parent component.

in your service.ts,

import { Subject } from 'rxjs/Subject'
import { Observable } from 'rxjs/Rx';

@Injectable()
export class myService {

  private pageName = new Subject<string>();

  pageNameChange$ = this.pageName.asObservable();
  changedComponentName(option:string){
        this.pageName.next(option);
  }
}

In your child components,

child component 1

public ngOnInit() {
  this.myService.changedComponentName('child1');
}

child component 2

public ngOnInit() {
   this.myService.changedComponentName('child2');
}

and so on..

Now, to get the changed Component names in your parent component,

parent component.ts

import { Subscription } from 'rxjs';

export class parentComponent {

    private subscription:Subscription;

    constructor(private myService:myService){

        this.myService.pageNameChange$.subscribe( /* get called on every child page changes*/
         newPageName => {

        console.log(newPageName); // you get your passed component name ( child1 / child2 /etc.. here in the 'newPageName' variable
    });
  }
}
Daniel Devadoss
3#
Daniel Devadoss Reply to 2017-11-14 17:53:24Z

Are you getting ? $event in your parent method?

If YES then why are you using let childDetails ={} inside parent class method . Instead you should use this.childDetails={}

onChildLoaded($event){
 this.childDetails ={ title: $event.childTitle, helperBar: $event.childHelperBar }; 
console.log (childDetails); 
}

and parent html shoul be

<div class="subheader"> <h1>{{ childDetails.title }}</h1> {{ childDetails.helperBar }} </div> 
<nav class="sidebar"> </nav> 
<main role="main" class="">
 <app-first-child (childLoaded)="onChildLoaded($event)"></app-first-child> </main>

If you don't want to use <app-first-child/> then you should use shared service

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.347564 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO