How to reload or refresh only child component in Angular 8
Asked Answered
S

6

52

I have two components, One parent and Other Child.

HTML Part

<div>
  <div class="row col-md-12">
    <div class="col-md-4">
       <!-- Some HTML Code of Parent component over here -->
    </div>
    <div class="col-md-8">
      <child-component></child-component>
    </div>
 </div>
 <button class="button" (click)="reloadOnlyChild($event)">Reload Child</button>
</div>

Now, On click of this button, I want the only child to get reload, or refresh.

TS Part

reloadOnlyChild(event){
  // I want to reload the child from here.
}

I searched on the Internet, I am getting for Vue or React, But not for Angular.

Sadye answered 5/11, 2019 at 11:24 Comment(3)
What do you mean by "reload" ? Have the *ngOnInit launch again ?Blanchette
Suppose, Child component consists is a form. I have filled that form. I on button click, I am saving data, And I want it to reload So that all fields of that form become Empty and untouched.Sadye
Can you post more code or better create a stackblitz about this.Lawabiding
M
68

Best way to update a child component is: ngOnChanges()

ngOnChanges(): "A lifecycle hook that is called when any data-bound property of a directive changes. Define an ngOnChanges() method to handle the changes." We use this lifecycle hook to respond to changes to our @Input() variables.

Example:

import { Component, Input, OnChanges } from "@angular/core";

@Component({
  selector: "child-component",
  templateUrl: "./child-component.html"
})
export class MyComponent implements OnChanges {
  @Input() someInput: string;

  constructor() {}

  ngOnChanges() {
  /**********THIS FUNCTION WILL TRIGGER WHEN PARENT COMPONENT UPDATES 'someInput'**************/
  //Write your code here
   console.log(this.someInput);
  }   
 
}

Use child component inside parent component as follows

<child-component [someInput]="inputValue"></child-component>
Muriah answered 23/6, 2020 at 6:35 Comment(4)
this scenario will fail if you are deleing with popupYanyanaton
Hey @ravipatel, no, it will not fail until you are not doing it right. What is the scenario you have?Muriah
I have a class which I pass to a child component, the class contains functions changing data inside itself, this is not change detected by Angular, So I simply added @Input() lastChanged?: Date; to the child and lastChanged?: Date; to the object which is updated locally inside functions. Pass it on to the child <child [obj]="obj" [lastChanged]="obj.lastChanged" /> and the child's ngOnChanges() gets called.Vizza
What if there are multiple inputs, like input1, input2, input3 and I only want the function to trigger on input2. How do we achieve/differentiate them?Lilywhite
R
31

Say if you have a form in Child.Component.ts and if you want to reset it from parent component you can establish a connection between parent and child using Subject.

Parent.Component.html

<child-component [resetFormSubject]="resetFormSubject.asObservable()"></child-component>
<button (click)="resetChildForm()"></button>

Parent.Component.ts

import { Subject } from "rxjs";
resetFormSubject: Subject<boolean> = new Subject<boolean>();

resetChildForm(){
   this.resetFormSubject.next(true);
}

Child.Component.ts

import { Subject } from "rxjs";
@Input() resetFormSubject: Subject<boolean> = new Subject<boolean>();

ngOnInit(){
 this.resetFormSubject.subscribe(response => {
    if(response){
     yourForm.reset();
    // Or do whatever operations you need.
  }
 }
}

By using Subject you can establish a connection from parent to the child whenever the button gets clicked.

Hope this answer helps! Cheers :)

Rianna answered 5/11, 2019 at 11:56 Comment(0)
K
19

You could add an Input to update the component, or add a update function in the child that you can call in the code. Using @ViewChild to call the child update function from the parent. Like this

( https://stackblitz.com/edit/angular-updatechild ):

Child:

import { Component } from "@angular/core";

@Component({
   selector: "app-child",
   templateUrl: "./child.component.html",
   styleUrls: ["./child.component.css"] 
})
export class ChildComponent {
   ticks = Date.now().valueOf();

   constructor() {}

   update(): void {
   this.ticks = Date.now().valueOf();
   }
}

Parent:

import { Component, OnInit, ViewChild } from "@angular/core";
import { ChildComponent } from "./../child/child.component";

@Component({
 selector: "app-parrent",
 templateUrl: "./parrent.component.html",
 styleUrls: ["./parrent.component.css"]
})
export class ParrentComponent implements OnInit {
  @ViewChild(ChildComponent, { static: false }) childC: ChildComponent;
  showChild: boolean = true;
  constructor() {}

  ngOnInit() {}

  onUpdateChild() {
    this.childC.update();
 }
}
Kith answered 5/11, 2019 at 14:41 Comment(0)
I
12

We can also use *ngIf and setTimeout to reset the child component from parent without making any change in child component.

.template:

.ts:

show:boolean = true

resetChildForm(){
   this.show = false;

   setTimeout(() => {
      this.show = true
    }, 100);
}

This is particularly helpful when we have no control over child component, like a 3rd party library component.

Idaliaidalina answered 20/2, 2020 at 9:53 Comment(0)
R
6

I used this approach and find it the easiest one. According to your code;

<!-- ParentComponent.html -->
<div>
  <div class="row col-md-12">
    <!--- Observe; I added something here --->
    <child-component [someValueToGetChanges]="ValueInput"></child-component>
 </div>
</div>

And then use ngOnChanges lifehook of angular in our childComponent. ngOnChanges method is called when any data-bound property of a directive changes. So in your childComponent, we'll do this;

export class ChildComponent implements OnChanges {
  @Input() 
  someValueToGetChanges: string;
  
  // this code is called when "someValueToGetChanges" value is changed by "ParentComponent"
  ngOnChanges() {
      // Code here what you want
      console.log(this.someValueToGetChanges);
  }   
  
  constructor() {}
}

Hope, it'll work for you as well!

Riser answered 8/6, 2022 at 14:6 Comment(0)
M
0

Suhas Parameshwara's answer is nice, but it's missing an unsubscribe to prevent memory leaks which might catch someone out who is copy pasting the solution. There's also a redundant Subject creation (it's also an Observable, not a Subject) which hides an error when you try to subscribe if you forget to pass in an Observable to the child.

Here's a more complete solution:

Parent.Component.html

<child-component [resetForm]="formResetter.asObservable()"></child-component>
<button (click)="resetChildForm()"></button>

Parent.Component.ts

import { Component } from '@angular/core';
import { Subject } from 'rxjs';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css'],
})
export class ParentClass {

  public formResetter: Subject<boolean> = new Subject<boolean>();

  resetChildForm() {
    this.formResetter.next(true);
 }
}

Child.Component.ts

import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
})
export class ChildClass implements OnInit, OnDestroy {
  @Input() resetForm: Observable<boolean>;

  private sub: any;

  ngOnInit() {
    this.sub = this.resetForm.subscribe(response => {
    // do whatever operations you need.
    });
  }

  ngOnDestroy(): void {
    this.sub.ngUnsubscribe();
  }
}
Marshall answered 19/1, 2023 at 3:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.