-1

I am working on an angular app. I have a input field. My code is as follows

<input matInput style="width:100%;" type="number" [ngModel]="input | number : '1.2-2'" (ngModelChange)="input = $event"   autocomplete="off">

stackblitz:

https://stackblitz.com/edit/ngx-slider-simple-slider-example-pl2peu?file=src%2Fapp%2Fapp.component.html

In this input field I am using number pipe. The problem I am facing with number pipe is if I enter a number in input field,then it is taking only 3 digits before decimal, if I try to enter 4th digit before decimal number disappers. I want to allow user to enter as many number as he wish before decimal. How can I resolve this?

R. Richards
  • 24,603
  • 10
  • 64
  • 64
julie
  • 35
  • 6
  • this is not how you can have thousand separators or decimals in input, see this : [https://stackoverflow.com/q/50147818/5747727](https://stackoverflow.com/q/50147818/5747727) – Mazdak Aug 10 '21 at 19:18

3 Answers3

0

I think your best bet is to implement ControlValueAccessor and create your own custom form control that formats the data the way that you want. This is a similar question and the accepted answer has a custom form control implementation that should put you on the right track,

How to format number input in angular

David Kidwell
  • 600
  • 1
  • 6
  • 15
0

Other options futhermore the comments

You can make something like this another SO. If you has a variable in .ts focus

focus:boolean=false;

You can write some like

<input matInput style="width:100%;" type="number" 
   [ngModel]="focus?inputTarget:(inputTarget | number : '1.2-2')" 
   (ngModelChange)="inputTarget = $event"  
   (blur)="focus=false" 
   (focus)="focus=true"  autocomplete="off">

Or you can make a directive

@Directive({
  selector: '[format]',
  exportAs: 'child'
})
export class FormatDirective implements OnInit {
  focus:boolean=false;
  value:any;
  @Input('format') formato:string
  @HostListener('blur') _(){
    this.focus=false;
    this.value=this.control.control.value;
    this.control.control.setValue(formatNumber(this.value,'en-US',this.formato))
  }
  @HostListener('focus') __(){
    this.focus=true;
    this.control.control.setValue(this.value)
  }
  constructor(private control:NgControl){}
  ngOnInit(){
    setTimeout(()=>{
      this.value=this.control.control.value;
      this.control.control.setValue(formatNumber(this.value,'en-US',this.formato))
    })
  }
}

The stackblitz

NOTE: If you "format" the number with thousand separators the type can not be "number"

Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • It is working fine for values before decimal. But once be click on input field it shows all the values after decimal. Is there is any way in your solution you can restrict it to always two values after decimal whether we click it or not – julie Aug 11 '21 at 05:15
  • I add a new answer mixing this answer and another one about mask. – Eliseo Aug 11 '21 at 08:16
0

if we want that not allow more than 2 decimals, we need mix the before answer and this SO

The directive can be like

@Directive({
  selector: '[decimal]'
})
export class DecimalDirective implements OnInit {
  
  @Input('decimal') set _(value){
    this.formato=value;
    const digits=value.split('-')[1]
    this.regExpr=new RegExp("^[+-]?([1-9]\\d*|0)?(\\.\\d\{0,"+digits+"\})?$");
  }
  
  private formato:string=null
  private _oldvalue: string = "";
  private regExpr: any;
  private el: HTMLInputElement;
  private control:AbstractControl;

  constructor(private elementRef: ElementRef,private ngcontrol:NgControl,@Inject(LOCALE_ID) private language) {
    this.el = this.elementRef.nativeElement;
    this.control=ngcontrol.control
  }
  @HostBinding('style.text-align') get="right"
  @HostListener('input', ['$event'])
  change($event) {

    let item = $event.target
    let value = item.value;
    let pos = item.selectionStart;
    let matchvalue = value;
    let noMatch: boolean = (value && !(this.regExpr.test(matchvalue)));
    if (noMatch) {
      item.selectionStart = item.selectionEnd = pos - 1;
      if (item.value.length < this._oldvalue.length && pos == 0)
        pos = 2;
      this.el.value=this._oldvalue;

      item.value = this._oldvalue;
      this.control.setValue(item.value)
      item.selectionStart = item.selectionEnd = pos - 1;
    }
    else
    {
      this._oldvalue = value;
    }
  }
  @HostListener("focus", ["$event.target.value"])
  onFocus() {
    if (this.formato)
    this.el.value = this._oldvalue;
  }

  @HostListener("blur", ["$event.target.value"])
  onBlur(value: any) {
    if (this.formato)
    this.transform(value);
  }
  ngOnInit() {
    setTimeout(()=>{
      this.transform(this.control.value);
  
    })
  }
  
  transform(value: any) {
    this._oldvalue = value;
    if (value && !isNaN(value)) {
      this.el.value=formatNumber(+this._oldvalue, this.language, this.formato);
      const formated=this.el.value.split(',').join('')
      if (formated.indexOf(this._oldvalue) >= 0) this._oldvalue = formated;
    }
  }
}

And you use as

<input [(ngModel)]="value" decimal="1.2-2">

See the stackblitz

Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • this works fine. But is it possible that instead of making a separate directive, we can handle same thing in hmtl code – julie Aug 11 '21 at 08:47
  • @Julie, he "key" is in (blur) not only make "focus=false" else call a function to change the inputTarget in the way has only two decimals:`format() { this.inputTarget=Math.round(+this.inputTarget*100)/100 }` and use `(blur)="focus=false;format()"` – Eliseo Aug 11 '21 at 09:28