0

I'm trying to implement a custom input that accepts only numeric values by reseting the rest to 0, using the following code for the input component:

import {Component, Input, Output, ElementRef, EventEmitter} from '@angular/core';
import {Observable} from 'rxjs/Rx';

@Component({
    selector: 'debounce-input',
    template: '<input type="text" [placeholder]="placeholder" [(ngModel)]="_v">'
})
export class DebounceInputComponent {
    @Input() placeholder: string
    @Input() delay: number = 300

    _v: string

    @Input()
    get v(): string {
        return this._v
    }

    set v(_value) {
        this._v = _value
        this.valueChange.emit(this.v)
    }

    @Output() valueChange: EventEmitter<any> = new EventEmitter<any>()

    @Output() value: EventEmitter<any> = new EventEmitter<any>()

    constructor(private elementRef: ElementRef) {
        const eventStream = Observable.fromEvent(elementRef.nativeElement, 'keyup')
            .map(() => this.v)
            .debounceTime(this.delay)
            .distinctUntilChanged()
        eventStream.subscribe((obj) => this.value.emit({v: this.v}))
    }
}

The component above is imported within AppComponent using the following code:

  1. HTML part:

    <div style="text-align:center">
      <debounce-input [v]="mynumber"
      delay="1000"
      placeholder="Type something..."
      (value)="handle($event)">
      </debounce-input>
    </div>
    
  2. TypeScript part:

    import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'app';
    
      mynumber = 0
    
      handle(obj) {
        console.log(obj.v)
        if (isNaN(Number(obj.v))) {
          console.log('trying to reset invalid input to 0')
          this.mynumber = 0
        }
      }}
    

The problem is whenever I type a non-numeric value, the AppComponent fails to reset the input to 0, although the "trying to reset invalid input to 0" message gets shown within the console.

What is the cause of this behavior?

13
  • what is the value of console.log(obj.v) ? did you try with obj.target.value? Commented Feb 15, 2018 at 10:54
  • @Niladri It's the same as any value I type in the input component. Commented Feb 15, 2018 at 10:56
  • do you think you could set up a stackblitz for us to play with you code? Commented Feb 15, 2018 at 10:57
  • @BorisLobanov I tried to do so, but stackblitz failed to detect the component I added. Commented Feb 15, 2018 at 11:01
  • Whats the issue the question explanation is to confusing?? Do you want to restrict users for your input fields as type="number" or say type="text" Commented Feb 15, 2018 at 11:02

2 Answers 2

1

I figured it out. You @Input value was not changed because mynumber in the parent was not changing from the child changes. I added this functionality and it worked:

handle(obj) {
    console.log(obj.v)
    if (isNaN(Number(obj.v))) {
      console.log('trying to reset invalid input to 0')
      this.mynumber = 0;
    } else {
      this.mynumber = obj.v; // add this line
    }
  }

P.S. I'd still, however, consider restricting your input to numeric type only and adding some filter to prevent setting numbers like '0123'.

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

4 Comments

I updated the code as you mentioned, but I am still getting the same problem - the input doesn't get reset to 0 after typing 'a'.
stackblitz.com/edit/angular-kscfaw works for me. have a look, maybe there's something you are missing?
I don't understand
I think the delay is causing the problem. If you type 1, then give it a second, then type 'a' it works correctly
0

modify the setter in your input component, and make ngModel pointing to the v instead of _v.

  import {Component, Input, Output, ElementRef, EventEmitter} from '@angular/core';
  import {Observable} from 'rxjs/Rx';

  @Component({
      selector: 'debounce-input',
      template: '<input type="text" [placeholder]="placeholder" [(ngModel)]="v">'
  })
  export class DebounceInputComponent {
      @Input() placeholder: string
      @Input() delay: number = 300

      _v: string

      @Input()
      get v(): string {
          return this._v
      }

      set v(_value) {
        if (isNaN(Number(_value))) {
          console.log('trying to reset invalid input to 0')
          this._v = '0';
          return;
        }
          this._v = _value
          this.valueChange.emit(this.v)
      }

      @Output() valueChange: EventEmitter<any> = new EventEmitter<any>()

      @Output() value: EventEmitter<any> = new EventEmitter<any>()

      constructor(private elementRef: ElementRef) {
          const eventStream = Observable.fromEvent(elementRef.nativeElement, 'keyup')
              .map(() => this.v)
              .debounceTime(this.delay)
              .distinctUntilChanged()
          eventStream.subscribe((obj) => this.value.emit({v: this.v}))
      }
  }

Comments

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.