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.

developer
  • 1,401
  • 4
  • 28
  • 73
  • 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. – JoannaFalkowska Jul 07 '22 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. – Thierry Falvo Jul 07 '22 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. – developer Jul 07 '22 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. – developer Jul 07 '22 at 13:09
  • Does this answer your question? [Call child component method from parent class - Angular](https://stackoverflow.com/questions/38974896/call-child-component-method-from-parent-class-angular) – Leonel Thiesen Nov 23 '22 at 17:30

3 Answers3

1

You can use the ViewChildren decorator.

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

saveProduct(productId) {
   this.childComponents.get(productIndex).onSave();
}
MoxxiManagarm
  • 8,735
  • 3
  • 14
  • 43
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"}
}
hashtag-assist
  • 402
  • 6
  • 12
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

Vito Neto
  • 54
  • 5
  • 1
    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. – developer Jul 07 '22 at 13:11
  • 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. – Vito Neto Jul 07 '22 at 14:01
  • I understood but I would like to keep the save button inside the parent component. – developer Jul 07 '22 at 14:07
  • Create a service.ts. import the service in child and parent component.ts. In the service you create - yourEvent = new EventEmitter(); 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 }) } – Vito Neto Jul 07 '22 at 14:39
  • I did it locally. So, your button will be in the parent, when clicked will run a function inside the child. – Vito Neto Jul 07 '22 at 14:42
  • thanks, it should allow to call the child component's method this way. However, how can I pass the form object to onSave(form) method? – developer Jul 07 '22 at 15:11