0

I'm trying to figure how to pass value from one Angular component to another my-input.component and my-button.component:

I'm trying to receive from my-input.component.ts and display @Input('name') with button (click)="displayReceivedValue()" from my-button.component.html in my-button.component.ts:

import { Component, Input, OnInit } from '@angular/core';
import { MyInput } from '../../interfaces/my-input';

@Component({
  selector: 'app-my-button',
  templateUrl: './my-button.component.html',
  styleUrls: ['./my-button.component.scss'],
})
export class MyButtonComponent implements OnInit {
  @Input('name')
  public input!: MyInput;
  constructor() {}

  ngOnInit(): void {}

  async displayReceivedValue() {
    console.log('Received value: ', this.input);
  }
}

which is <app-my-button name=""></app-my-button> component in Login page login.component.html from my-input.component.ts with this.myValue from [(ngModel)]="myValue" in input of my-input.component.html, but I'm not sure, how to pass it to name="":

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

@Component({
  selector: 'app-my-input',
  templateUrl: './my-input.component.html',
  styleUrls: ['./my-input.component.scss'],
})
export class MyInputComponent implements OnInit {
  
  public myValue: any;

  constructor() {}

  ngOnInit(): void {}
}

Also I've tried use @Output() with <app-my-button (inputValue)="acceptData($event)"></app-my-button> component in Login page from my-input.component.ts:

import { Component, EventEmitter, OnInit, Output } from '@angular/core';
    
    @Component({
      selector: 'app-my-input',
      templateUrl: './my-input.component.html',
      styleUrls: ['./my-input.component.scss'],
    })
    export class MyInputComponent implements OnInit {
      @Output() inputValue= new EventEmitter<string>();
        
      public myValue: any;

      constructor() {}
    
      ngOnInit(): void {
           this.inputValue.emit(this.inputValue);
      }
    }

in my-button.component.ts:

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

@Component({
  selector: 'app-my-button',
  templateUrl: './my-button.component.html',
  styleUrls: ['./my-button.component.scss'],
})
export class MyButtonComponent implements OnInit {
  constructor() {}
  ngOnInit(): void {}
  acceptData(data: any) {
    console.log(data);
  }
}

I got nothing if I add (inputValue)="acceptData($event) to my-button.component.html, or if I add (inputValue)="acceptData($event) to login.component.html I got error:

TS2339: Property 'acceptData' does not exist on type 'LoginComponent'.

1 Answer 1

2

Option 1: Using ControlValueAccessor

Try to make it simple; Lets say you have below in your app component

app.component.html

<app-my-input [(ngModel)]='myValue'></app-my-input>
<app-my-button [name]='myValue'></app-my-button>

app.component.ts

 myValue = 'MyValue'

Basically we are binding to the same value in the app.component.ts. So the value will be updated to the button name property when it changes.

Now if you try to run above you will receive an error

No value accessor for control with the name app-my-input

That is because we are binding to the ngModel that requires to implement ControlValueAccessor. So we implement this like below

my-input.component.ts

@Component({
  selector: 'app-my-input',
  templateUrl: './my-input.component.html',
  styleUrls: ['./my-input.component.css'],
    providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => MyInputComponent),
      multi: true
    },
    ]
})
export class MyInputComponent implements ControlValueAccessor {
  
  myValue = '';
  constructor() { }
  writeValue(value: any): void {
    if (value !== undefined) {
      this.myValue = value;
    }
  }
  onChanges: ($value: any) => void;
  onTouched: () => void;

  registerOnChange(fn: any): void {
    this.onChanges = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
}

my-input.component.ts

<input [(ngModel)]='myValue' (ngModelChange)='onChanges(myValue)'>

Now our app-my-input works just like a normal input and we can bind to the [(ngModel)] directive

So now in our app-my-button we can receive this using @Input decorator

app-my-button.ts

  @Input() name = "";
  constructor() {}

  ngOnInit(): void {}

  displayReceivedValue() {
    console.log("Received value: ", this.name);
  }

app-my-button.html

<button (click)='displayReceivedValue()'>My button</button>

Now if you click on the button you will see a log in the console with the value of the input

Demo Here

Option 2: Using @Output and @input decorators

To use @input and @Output you would simply define you are input with something like

export class MyInputComponent implements OnInit {
  
  @Input() input = '';
  @Output() output: EventEmitter<string> = new EventEmitter()
  myValue = '';
  constructor() { }
  onChanges = ($event) => {
    this.output.emit($event)
  }

  ngOnInit() {
    this.myValue = this.input
  }
}

and in the html

<input [(ngModel)]='myValue' (ngModelChange)='onChanges(myValue)'>

Now we bind to (ngModelChange). When the value changes, we emit the value using the output property defined as an EventEmitter<string>

We can then receive this with

<app-my-input [input]='myValue' (output)="myValue = $event"></app-my-input>

See this Demo

Sign up to request clarification or add additional context in comments.

2 Comments

Hello! Sorry for the late reply. So I've to use 'ngModel' and 'name' in 'app-my-input' and 'app-my-button' components on 'app.component.html' from '[(ngModel)]="myValue" (ngModelChange)="onChanges(myValue)"' in 'my-input.component.html', provided code gives the required result and I will be marked as an answer, but as I am new with Angular, I'm still trying to figure out, how to use 'output' and 'Input' in the same task. I'm looking into Angular documentation angular.io/guide/inputs-outputs, but looks like I'm missing something because the value is always undefined
See my approach above in the updated solution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.