1

I was trying to create a custom input component with debounce, so I followed this suggestion

Debounce works, but at the beginning the input value is not correctly set to the input component.

This is how I implemented it:

app.component.ts

import { Component } from '@angular/core';
import { DebInputComponent } from './deb-input/deb-input.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
  test:string ='test';
}

app.component.html

  <deb-input [(ngModel)]="test" type="text" label="Test" ngDefaultControl>
  </deb-input>
<div>{{test}}</div>

deb-input.component.ts

import { Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
import { Component, Input }   from '@angular/core';

@Component({
  selector: 'deb-input',
  templateUrl: './deb-input.component.html',
  styleUrls: ['./deb-input.component.css'],
  providers: []
})

export class DebInputComponent {
    @Input() label: string;
    @Input() type: string="text";
    @Input() model: string;
    modelChanged: Subject<string> = new Subject<string>();

    constructor() {
     this.modelChanged
      .pipe(debounceTime(1000))
      .pipe(distinctUntilChanged())
      .subscribe(newValue => {this.model = newValue;
        console.log(this.model)});
    }

    changed(text: string) {
        this.modelChanged.next(text);
    }
}

deb-input.component.html

 <div>
 <span>{{label}}</span>
 <input [(ngModel)]='model' (ngModelChange)='changed($event)' [type]='type' ngDefaultControl/>
</div>

How can I make sure that model inside deb-input is correctly set to "test"?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Igino Boffa
  • 686
  • 1
  • 9
  • 21
  • You should use ControlValueAccessor - https://angular.io/api/forms/ControlValueAccessor if you want to implement custom form control.. this is the recommended way – Abinesh Devadas Jun 19 '18 at 12:59

1 Answers1

2

You're using ngmodel whereas you should use the name of your component input

<deb-input [model]="test" type="text" label="Test" ngDefaultControl>
  </deb-input>

Edit

If you want a two way binding for your component, just add a eventEmitter to your component like this:

@Input() model: string;
@Output() modelChange = new EventEmitter<string>();
modelChanged: Subject<string> = new Subject<string>();
@Output() modelChangeEvt = new EventEmitter<string>();

 constructor() {
 this.modelChanged
  .pipe(debounceTime(1000))
  .pipe(distinctUntilChanged())
  .subscribe(newValue => {this.model = newValue;
    this.modelChangeEvt.emit(newValue);
    console.log(this.model)});
}

Then use the 2 way binding in HTML:

<deb-input [(model)]="test" type="text" label="Test" ngDefaultControl></deb-input>
Igino Boffa
  • 686
  • 1
  • 9
  • 21
Melchia
  • 22,578
  • 22
  • 103
  • 117