0

I am trying to pass an input value from a select input that has a (change) event associated with it from child component to parent element. Would like the variable to get updated every time the variable from the child component is updated.

My question is different from Question, due to my variable changes on a change event and needs to be updated every time the variable changes.

I was able to figure this out using ViewChild and AfterViewInit but I get an error in the console saying: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'Testing'.

Figured there has to be an easy way of doing this. Keep in mind I am still new with Angular.

Child Component template:

<form>
  <div class="form-group">
    <label for="Master-Products">Select Master Product</label>
    <select [(ngModel)]="selectedValue" name="pow" (change)="pow = $event.target.value; onKeyUp()" class="form-control" id="Master-Products">
      <option *ngFor="let pow of powers" [value]="pow">{{pow}}</option>
    </select>
  </div>
</form>

Child-component:

export class MasterInputComponent {
  powers: any[] = [ 'power1', 'power2', 'power3' ];
  submitted = false;
  pow:string = 'Testing';
  selectedValue = null;
  constructor() { }

  onKeyUp(value): void{
    console.log('Value: ',this.pow);
  }

Parent-Component-Template:

<div role="tabpanel" class="tab-pane" id="accessories">
  <h1>ACCESSORIES</h1>
  <h4>Testing: {{power}}</h4>
  <master-input (change)="recieveMessage($event.target.value)"></master-input>
  <accessories></accessories>

Parent-Component:

export class AppComponent implements AfterViewInit{
  @ViewChild(MasterInputComponent) child;
  title = 'Having FUN with Angular';
  posts: any[];
  power:string;

  constructor(private service:ProductsService){}
  ngAfterViewInit(){
    this.power = this.child.pow;
  }

  recieveMessage(value){
    console.log('Event: ',value);
    this.power = value;
    console.log('Favorite has changed')
  }

Any help would be greatly appreciated, thank you!

Travis Michael Heller
  • 1,210
  • 3
  • 16
  • 34
  • You would want `Output` and an EventEmitter in this case :) https://angular.io/guide/component-interaction#parent-listens-for-child-event – AT82 Oct 04 '17 at 16:23
  • Possible duplicate of [Pass data from child to parent component Angular2](https://stackoverflow.com/questions/42107167/pass-data-from-child-to-parent-component-angular2) – AT82 Oct 04 '17 at 16:24
  • I tried this before my current solution and I got an error as well. I do not remember the error. Both ways work but I still end up with an error in the console. Would you mind showing me an example? Most likely your way is different than how I implemented it. – Travis Michael Heller Oct 04 '17 at 16:25
  • I reverted back to when I used the EventEmitter and the error i get is: Cannot read property 'target' of undefined. My app is not broken but i still get that error in console. – Travis Michael Heller Oct 04 '17 at 16:27
  • 1
    That should work... :) https://stackblitz.com/edit/angular-wga92l?file=app%2Fhello.component.ts – AT82 Oct 04 '17 at 16:41
  • I tried your code and I get this error: ERROR TypeError: _co.hasChanged is not a function in my console. plus the value doesn't change next to the word testing on my app and in the example you posted instackblitz. any ideas? Thanks for your help by the way. – Travis Michael Heller Oct 04 '17 at 16:45
  • 1
    I updated my stackblitz a bit, so if you check now, it assigns the value to the variable. Best would be now in this case is that you take the stackblitz, apply your code to it which showcases the error, much easier to help that way :) – AT82 Oct 04 '17 at 16:47
  • 1
    Perfect, thank you so much! Will be dissecting your answer for a bit to completely understand what you did. – Travis Michael Heller Oct 04 '17 at 16:53
  • You are very welcome! Dissect away :P and come back if you have question :) – AT82 Oct 04 '17 at 16:55

2 Answers2

0

do the following steps in your code :

(ngModelChange)="onKeyUp($event)" instead of (change)="pow = $event.target.value; onKeyUp()"

in your child ts file

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

@Output() sendMessage = new EventEmitter();

onKeyUp(e) {
    this.sendMessage.next(e);
}

parent html

<master-input (sendMessage)="recieveMessage($event)"></master-input>
  <accessories></accessories>

the following code will add your parent ts

recieveMessage(msg) {
    console.log('msg', msg)
}
Chandru
  • 10,864
  • 6
  • 38
  • 53
0

Try this:

constructor(private service:ProductsService, private cdr: ChangeDetectorRef){}
ngAfterViewInit(){
    this.power = this.child.pow;
    this.cdr.detectChanges();
}

This link will throw light on the exact cause of the issue.

Surender Khairwa
  • 601
  • 4
  • 17
  • I actually read this in another article when I typed my error code into google. Did not end up helping me nor did I quite understand the solution. – Travis Michael Heller Oct 04 '17 at 17:28
  • The SO link I provided has discussed this issue extensively. And on of the comments in the answer pointed to the same issue that you are facing! – Surender Khairwa Oct 04 '17 at 17:47
  • As I mentioned earlier, I already read that article and did not like the solution as I do not fully understand the reasoning behind it. I am also new to angular and would prefer to understand my code rather than just pasting some answer cause it might make my code work. I have already found an answer to my question in the above comments from @AJT_82. when I have extra time I will dig further into your solution and the making behind it. – Travis Michael Heller Oct 04 '17 at 18:16
  • When I go back to try your solution later in the day and find out it works for my situation, I will mark your solution as the answer. Thank you for your time. – Travis Michael Heller Oct 04 '17 at 18:22