prajeesh
prajeesh

Reputation: 2382

Angular4 - Call a method from parent component to child modal component

i have a parent componet(profile-characteristics.component.ts) and a child modal component(pc-predefined-list.component.ts).

When a drop down option is changed in the parent component template, i need to show its corresponding values in the child modal template.

The child component method is as follows.

 constructor(
    private utilsService: UtilsService,
    private route: ActivatedRoute,
    private _fb: FormBuilder,
    @Inject(DOCUMENT) private document: Document
  ) {}

  ngOnInit() {
    this.pListValueForm = this._fb.group({
      pListValues: this._fb.array([this.initItemRows()]) // here
    });
    //this.setListValues();
    this.route.params.subscribe(params => {
      this.accountId = params['id'];
    });
  }
setListValues() {

    this.pListValueForm = this._fb.group({
      pListValues: this._fb.array([]) // here
    });

    const control = <FormArray>this.pListValueForm.controls['pListValues'];
    this.selectedListValues.forEach(x => {
      control.push(this.patchValue(x.profile_characteristic_list_value_id, x.name, x.sort_order))
    });
  }

parent component

  ngAfterViewInit() {
// child is set
this.child.setListValues();

}

The modal will work correctly if i hard code this.selectedListValues as follows.

this.selectedListValues = [ { "profile_characteristic_list_value_id": "13110afd-f459-11e7-9d12-408d5cbccb60", "profile_characteristic_list_id": "1", "name": "value 2", "sort_order": "2" }, { "profile_characteristic_list_value_id": "13110e5f-f459-11e7-9d12-408d5cbccb60", "name": "value 4", "sort_order": "4", "profile_characteristic_list_id": "2", } ];

I need to pass the "selectedListValues" dynamically from parent component to the child component. Any ideas on how to achieve this?

Upvotes: 0

Views: 1527

Answers (3)

Marco Barbero
Marco Barbero

Reputation: 1538

I have used this pattern many times and it works great!

Two component (a parent component and its children or other different component) can share a service whose interface enables bi-directional communication.

Like in the Observer pattern, in this case the scope of the service instance is the notification from a component (Publisher) and other componentents (Subscriber).

To pass to the child the complex data type (like your "selectedListValues") I usually use an external class which represents with its fields tha data:

model.ts

export class ListValues
{
    public profile_characteristic_list_value_id: string;
    public profile_characteristic_list_id: number;
    public name: string;
    public sort_order: string;
}

mycomponent.service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { ListValues} from './model';
@Injectable()
export class MyComponentService{
    // Observable 
    private sampleObservable = new Subject<ListValues>();
    // Observable boolean streams
    sampleSubscriber = this.sampleObservable.asObservable();
    // Event for notification from publisher to subscriber
    sampleEventChanged(value:ListValues)
    {
        this.sampleObservable.next();
    }
}

In the component who wants to notify all subscribers a change of its state:

mycomponent-publisher.ts (for you is the parent component)

import { Component } from '@angular/core';
import { MyService } from './mycomponent.service';

@Component({
  selector: 'app-my-control-publisher',
  template: `
  <h2>This is the publisher control</h2>
  <button (click)="announce()">Announce to subscriber</button>
  `,
  providers: [MyService]
})

export class MyControlPublisherComponent 
{
  constructor(private myService: MyService) { }

  announce() 
  {
      listValues = new ListValues();
      // here set the info to notify...
      this.myService.sampleEventChanged(listValues);
  }
}

In the subscriber component who want to get the notification.

mycomponent-subscriber.ts (for you is the child component)

import { Component, OnDestroy } from '@angular/core';
import { MyService } from './mycomponent.service';
import { Subscription } from 'rxjs/Subscription';
import { ListValues} from './model';

@Component({
 selector: 'app-my-control-subscriber',
 template: `
 <h2>This is the subscriber control</h2>
 `,
})

export class MyControlSubscriberComponent 
{
  // Subscriptions
  private componentSubscription: Subscription;

  constructor(private myService: MyService) 
  {
    // Subscription of the notifications
    this.componentSubscription= this.myService.sampleSubscriber.subscribe(value =>
    {
      // Put the code for manage the notification here
      // value is of type 'ListValues'
    }
  }

  ngOnDestroy()
  {
    // Release subscription to avoid memory leaks when the component is destroyed
    this.componentSubscription.unsubscribe();
  }
}

Upvotes: 0

Berlin_Bro
Berlin_Bro

Reputation: 109

You have two options that come to mind:

1) Make the child component a Viewchild of the parent, allowing you to to call the child elements function from the parent component and passing the selectedListValues as a parameter. How you trigger the function call is up to you.

2) Use data binding. Define an Output in the parent component from your list selection, emitting the list. Then implement an Input in the child component to bin a list as a property. Passing that list every time the selection from your parent component is updated, could trigger a function displaying the list for example. See here Let me know if you need more help or code examples, but i am a fan of learning by doing in terms of longterm imporvement.

Have fun coding

Upvotes: 0

user4676340
user4676340

Reputation:

If it were my issue, I would create an Input into your child component :

@Input() chosenValue: any;

Then passe a value to the child :

<app-pc-predefined-list [chosenValue]="YourParentVariable"></app-pc-predefined-list>

The, I would make my child implement onChanges :

export class PcPredefinedListComponent implements OnChanges {
  // Your code ...

  ngOnChanges(changes: SimpleChanges) {
    console.info(changes);
  }
}

This way, everytime your parent's list is changed, your child will be notified and will be able to launch your method to filter the choices of your list.

Upvotes: 1

Related Questions