1

I have a parent component having three instances of child component inside it.

child-product-detail.component.html

<form id="frmProduct" #frmProduct="ngForm" (ngSubmit)="onSave(frmProduct)">
   <ng-content select="[buttons-view]"></ng-content>
   <input type="text" id="txtProductName" name="txtProductName" [(ngModel)]="product.productName" />
</form>

child-product-detail.component.ts

onSave(form) {
    let isValid = this.validate(form);
    if (!isValid) return;
}

parent-product.compoment.html

<child-product-detail [product]="products[0]">
   <div buttons-view>
       <button type="button" class="btn" (click)="saveProduct(0)" >Save</button>                                    
   </div>
</child-product-detail>
<child-product-detail [product]="products[1]">
   <div buttons-view>
       <button type="button" class="btn" (click)="saveProduct(1)" >Save</button>                                    
   </div>
</child-product-detail>
<child-product-detail [product]="products[2]">
   <div buttons-view>
       <button type="button" class="btn" (click)="saveProduct(2)" >Save</button>                                    
   </div>
</child-product-detail>

parent-product.component.ts

saveProduct(productId) {
    let productToSave = this.products(productIndex);
    // Code required to call onSave method of child component
}

Is there anyway I can call onSave method of the child component passing the form object of it?

Thanks.

5
  • 1
    Maybe it could be possible to do that by using @ContentChildren, but you would be much better off if you posted the full description of what you're trying to accomplish and solved that actual problem in a different way. You're trying to do something that's usually an anti-pattern, for reasons that are very unclear. Commented Jul 7, 2022 at 11:39
  • why do you need to inject button-views content, and not add it directly in your child-product-detail.component.ts. Then use *ngFor to avoid to repeat 3 times same block. Commented Jul 7, 2022 at 12:49
  • @ThierryFalvo - I would like to reuse the child-product-detail at multiple places so I am trying to extract the functionality out of the child-product-details page. Commented Jul 7, 2022 at 13:08
  • @JoannaFalkowska - As mentioned in the above comment, I am trying to reuse the child-product-detail so I am trying to extract the save functionality in the parent page. Commented Jul 7, 2022 at 13:09
  • Does this answer your question? Call child component method from parent class - Angular Commented Nov 23, 2022 at 17:30

3 Answers 3

3

You can use the ViewChildren decorator.

@ViewChildren(ChildProductDetailComponent)
childComponents: QueryList<ChildProductDetailComponent>;

saveProduct(productId) {
   this.childComponents.get(productIndex).onSave();
}
Sign up to request clarification or add additional context in comments.

Comments

0

You can use an eventemitter.

Assuming you have the child component with an output event function like this:

<app-product-stock (outputStockEvent)="outputStockEvent($event)"></app-product-stock>

Then this would be the function in the parent:

public outputStockEvent(event){
    this.stock = event
  }

and in the child component:

    constructor(private fb: FormBuilder) {
        this.stockForm = this.fb.group({
          a: '',
          b: '',
          c:'',
        });
       }

.....
 

    ngOnInit(): void {
        this.stockForm.valueChanges.subscribe(data =>{
          this.outputStockEvent.emit(data)
        })
      }

If you then use a "Save" button in the ParentComponent, you can write the values into a final array:

public save(){
  let finalObj ={ "stock":this.stock"}
}

Comments

0

Yes, you can do it using the @Output directive to emit custom events.

For example:

child-product-detail.component.ts

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

export class ChildProductDetailComponent {
    @Output() yourEventEmitter = new EventEmitter<any>();

    onSave(form) {
        let isValid = this.validate(form);
        if (isValid) {
            this.yourEventEmitter.emit(form)
        };
    }

When onSave() is executed, it emit the yourEventEmitter

parent-product.compoment.html

<child-product-detail (yourEventEmitter)="saveProduct($event)">
    <button type="button" class="btn" (click)="onSave(0)" >Save</button>
</child-product-detail>

Than the parent component got the event and run the function saveProduct() and receiving the form by the $event.

parent-product.component.ts

saveProduct(productId) {
    // the productId is the form from the child component
}

You cand learn more about it https://angular.io/api/core/EventEmitter

6 Comments

Thanks @VitoNeto, however in this case I will have to add the save button in the child-product-details page so it will invoke the onSave method.
Yes, you still can do it how i'm saying, you just put the button inside the child component and call function that emit the event. Got it? I edited the parent-product.compoment.html to you see.
I understood but I would like to keep the save button inside the parent component.
Create a service.ts. import the service in child and parent component.ts. In the service you create - yourEvent = new EventEmitter<any>(); In the parent your function will Emit the event - this.service.yourEvent.emit(); In the child you wait to the subscribe of yourEvent - ngOnInit() { this.service.yourEvent.subscribe(() => { // here you take the form pass to service and take from the service to the parent }) }
I did it locally. So, your button will be in the parent, when clicked will run a function inside the child.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.