0

I have a parent component which is passing some data (selectedId) to the child component using @Input().

Parent Template

<child-component [selectedId]="selectedId"></child-component>

The child component is using the selectedId as follows:

Child Template

<select [(ngModel)]="selectedId">
  <option [value]="option.id" *ngFor="let option of options">{{option.name}}</option>
</select>

Child Component

export class HelloComponent  {
  @Input()
    set selectedId(id: any) {
      this._selectedId = id;
  }
  get selectedId() {
    return this._selectedId;
  }

  public _selectedId;

  options = [
      {
        "id": "1",
        "name": "Weekly"
      },
      {
        "id": "2",
        "name": "Bi-Weekly"
      },
      {

        "id": "3",
        "name": "Lunar"
      },
      {
        "id": "4",
        "name": "Monthly"
      }
  ]
}

This works perfectly. The problem is when I change the selected item straight from the child component - not using the parent component.

This is the following scenario when it doesn't work as expected:

  1. The selectedId gets populated from a parent component (API call)
  2. The use manually changes select options (from child-component)
  3. API gets called again, and it should set the same ID as it set on step 1. How ever this doesn't trigger the change event. My assumption is that parent component isn't aware of the manual change done in a child-component, therefore it still holds a reference to the selectedId from step 1, and doesn't trigger the change in step 3 because it's the same ID.

I recreated the problem on Stackblitz

I am aware that I can use Output() and shared services to solve this, but is there any other way that I could inform the parent about that change detection?

Dino
  • 7,779
  • 12
  • 46
  • 85
  • This can be done using `EventEmitter`. I have modified your stack blitz to provide the solution. Please take a look at it. Hope it helps. https://stackblitz.com/edit/angular-32ckgk?file=src/app/hello.component.ts – Suhas Parameshwara Aug 29 '19 at 09:46

2 Answers2

4

you can use @Output to notify the parent comonent when there is change in the child component something like this


@Component({
  selector: 'hello',
  templateUrl: './hello.component.html',
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent  {
  @Input()
    set selectedId(id: any) {
      this._selectedId = id;
      console.log('Child change event --> ', id);
  }
  get selectedId() {
    return this._selectedId;
  }

  @Output() selectedIdChange=new EventEmitter();

  public _selectedId;

  options = [
      {
        "id": "1",
        "name": "Weekly"
      },
      {
        "id": "2",
        "name": "Bi-Weekly"
      },
      {
        "id": "3",
        "name": "Lunar"
      },
      {
        "id": "4",
        "name": "Monthly"
      }
  ]
  onChangeSelectedId(){
    this.selectedIdChange.emit(this.selectedId);
  }
}

and set the value like this

<hello [(selectedId)]="selectedId"></hello>

Hana Wujira
  • 870
  • 7
  • 17
2

Approach 1: add this variable to a shared service and use it from there. It will get updated whenever child or parent modifies it.

Approach 2: pass an input from parent to child and add an event emitter so whenever values changes in child , you should emit an event to update value in parent component

Barkha
  • 702
  • 3
  • 8