Search code examples
angularangular2-components

Two way data binding for object between components


I have component with input:

<my-input *ngIf='filter.type === checkType.INPUT_TEXT' [filter]='filter'></my-input>

export class MyInputComponent{
  @Input() filter: any;
}

Template of MyInputComponent

<input name="name" [(ngModel)]="filter.input">

I want to set filter input inside and have influence on outer Component object.

How to pass filter object into MyInputComponent to achieve 2 way data binding?

I want to achIeve something like [(ngModel)]="filter.value" but working between Components

Other posts here about 2-way data binding does'nt answer my questions.

Edit:

After using extends DefaultValueAccessor in my MyInputComponent my parent component input disapears without any error.

import { Component, Input, OnInit, Provider, forwardRef } from '@angular/core';
import { FORM_DIRECTIVES, NG_VALUE_ACCESSOR, DefaultValueAccessor } from '@angular/common';

@Component({
  moduleId: module.id,
  selector: 'my-input',
  directives: [FORM_DIRECTIVES],
  host: { '(keyup)': 'doOnChange($event.target)' },
  templateUrl: '<input name="name" [(ngModel)]="filter.input">'
})

export class MyInputComponent extends DefaultValueAccessor {
  @Input() filter: any;

  onChange = (_) => {};
  onTouched = () => {};

  writeValue(filter:any):void {
    if (filter !== null) {
      super.writeValue(filter.toString());
    }
  }
  doOnChange(filter) {
    this.onChange(filter);
  }
}

const MY_VALUE_ACCESSOR = new Provider(
  NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => MyInputComponent), multi: true});

Solution

  • You need to implement a custom value accessor for this. Here is a sample of this:

    const MY_VALUE_ACCESSOR = new Provider(
      NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => MyInputComponent), multi: true});
    
    @Component({
      (...)
      providers: [ MY_VALUE_ACCESSOR ]
    })
    export class MyInputComponent extends DefaultValueAccessor {
      onChange = (_) => {};
      onTouched = () => {};
    
      writeValue(value:any):void {
        if (value!=null) {
          super.writeValue(value.toString());
        }
      }
    
      // call when your internal input is updated
      doOnChange(val) {
        this.onChange(val);
      }
    }
    

    For more details, see this article (section "NgModel-compatible component"):

    See also this question: