Possible to use pipe formatter of Angular inside t

2019-07-21 00:07发布

I've declared a format for splitting large numbers in groups of three digits and use it frequently like this.

<div>Huge number: {{ i_am_huge | make_threesome }}</div>

Now, there's a request for corresponding functionality but implemented in an input control like this one.

<input id="numeroUno"
       type="text">

The approach I can think of is to listen to typing and for each key perform a reformatting of the contents of the box like so.

<input id="numeroUno"
       type="text"
       (keyup)="formatify">

However, while this approach would work, I can't stop wondering if it's too much of Q&D, so before I build a whole control fauna around this paradigm, I'd like to get more info.

The usual googling didn't give me much. However, give a rather unusual nature of the requirement, it might be hard to find.

The assumption at this point is that input control isn't supposed to be used that way, which explains the clunkyness of my approach.

2条回答
走好不送
2楼-- · 2019-07-21 00:25

I would think that you should rather use an (attribute) directive here. You can use directives for validation purposes, so why not use it to do formatting in your input fields (actually trying to do something like this in my own project at the moment).

Basically it would somewhat look like that (example from the angular docs):

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {

  constructor(private el: ElementRef) { }

  @Input('appHighlight') highlightColor: string;

  @HostListener('mouseenter') onMouseEnter() {
    this.highlight(this.highlightColor || 'red');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.highlight(null);
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

This way you can manipulate the values inside of the input field and listen on events like click.

Another thing you have to do before it works: Add the directive (very similar to [ngStyle] or [ngClass]) to your input filed via [your-directives-name]. Look at the following code snippet and how it's done:

<h1>My First Attribute Directive</h1>

<h4>Pick a highlight color</h4>
<div>
  <input type="radio" name="colors" (click)="color='lightgreen'">Green
  <input type="radio" name="colors" (click)="color='yellow'">Yellow
  <input type="radio" name="colors" (click)="color='cyan'">Cyan
</div>
<p [appHighlight]="color">Highlight me!</p>
查看更多
男人必须洒脱
3楼-- · 2019-07-21 00:37

Use a Directive. In stackblitz you can see how work.

The directive store in the variable "value" the string without spaces. Each a change happens (I use @HotListener(input)) get the position of the cursor, get the value of the element, remove spaces, formate the number and put the cursor in the position

@Directive({ selector: "[testPipe]" })
export class TestPipe  implements OnInit {

  private el: HTMLInputElement;
  private value: any;
  constructor(@Optional() private ngControl:NgControl,
                private elementRef: ElementRef) {
    this.el = this.elementRef.nativeElement;
  }
  @HostListener("input", ["$event.target.value"])
  onInput() {
    let pos = this.el.selectionStart; //get the position of the cursor
    this.value = this.el.value.replace(/ /gi, ""); //store the value without spaces
    if (this.value.length%3==1) //If we must add an extra space
      pos++;
    //Yes, it's a "bizarro" way to separate in group of three 
    this.el.value=this.value.match(/(.+?)(?=(.{3})+(?!.)|$)/g).join(' ');
    //this.el.value=this.value.match(/(\d+?)(?=(\d{3})+(?!\d)|$)/g).join(' ');
    //Finally give the position of cursor
    this.el.selectionStart = this.el.selectionEnd = pos;
    if (this.ngControl)
        this.ngControl.control.setValue(this.el.value,{emit:false})

  }
  ngOnInit()
  {
    this.value = this.el.value.replace(/ /gi, "");
    this.el.value=this.value.match(/(.+?)(?=(.{3})+(?!.)|$)/g).join(' ');
//  this.el.value=this.value.match(/(\d+?)(?=(\d{3})+(?!\d)|$)/g).join(' ');
    if (this.ngControl)
        this.ngControl.control.setValue(this.el.value,{emit:false})

  }
}

Update I add a @Optional() ngControl:NgControl in constructor, so, if the directive is applied to a ngControl (the input belong to a formGroup or has a [(ngModel)], change the value too

查看更多
登录 后发表回答