在Angular 6指令中格式化数字/货币

时间:2019-07-10 06:48:22

标签: angular format currency angular-directive

我创建了一个货币指令,将在需要货币格式的每个输入元素中使用

所以我有2个主机侦听器,一个是OnFocus,第二个是Blur

它运行完美。但是当通过绑定设置输入值时,我需要格式化输入值

因此,当我打开模态时,我会得到未格式化的值... NgOnInit不起作用,因为它提早了太多

这是我的指令代码。

import { Directive, HostListener, Input, OnInit, ElementRef, AfterViewInit, OnChanges, Renderer2, ViewChild } from '@angular/core';

import { CurrencyPipe, getCurrencySymbol } from '@angular/common';

import { NgControl, ControlValueAccessor } from '@angular/forms';

import { CustomCurrencyPipe } from '../pipes/custom-currency.pipe';

import { ModalDirective } from 'ngx-bootstrap/modal';



@Directive({

  selector: '[appCurencyFormat]',

  providers: [CustomCurrencyPipe]

})



export class CurrencyFormatDirective implements OnInit{

  //@Input('appNumberFormat') params: any;

  @Input() decimalNumber: number = 2;

  @Input() symbol: string = "symbol";

  //@Input() OnlyNumber: boolean;

  local: string;

  decimal: string;

  currency: string;

  element: any;



  @ViewChild(ModalDirective) childModal: ModalDirective;



  constructor(private elementRef: ElementRef, private ngControl: NgControl, private currencyPipe: CustomCurrencyPipe, private _renderer: Renderer2) {


    this.element = this.elementRef.nativeElement;    

  }



  @HostListener('keydown', ['$event']) onKeyDown(event) {

    let e = <KeyboardEvent>event;

    //190 in array for .

      if ([46, 8, 9, 27, 13, 110].indexOf(e.keyCode) !== -1 ||

        // Allow: Ctrl+A

        (e.keyCode === 65 && (e.ctrlKey || e.metaKey)) ||

        // Allow: Ctrl+C

        (e.keyCode === 67 && (e.ctrlKey || e.metaKey)) ||

        // Allow: Ctrl+V

        (e.keyCode === 86 && (e.ctrlKey || e.metaKey)) ||

        // Allow: Ctrl+X

        (e.keyCode === 88 && (e.ctrlKey || e.metaKey)) ||

        // Allow: home, end, left, right

        (e.keyCode >= 35 && e.keyCode <= 39)) {

        // let it happen, don't do anything

        return;

      }

      // Ensure that it is a number and stop the keypress

      if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {

        e.preventDefault();

      }    

  }  



  @HostListener('focus', ['$event.target.value'])

  onFocus(value: any) {

    this.ctrl.setValue(this.currencyPipe.convertToNumber(value));    

  }



  @HostListener('blur', ['$event.target.value'])

  onBlur(value: any) {

    this.ctrl.setValue(this.currencyPipe.transform(value, this.decimalNumber, this.symbol));

  }



  get ctrl() {    

    return this.ngControl.control;

  }

}

我的解决方案是在ngOnInit中设置间隔...

ngOnInit() {
        let m = window.setInterval(() => {
        console.log("Upao sam");
        console.log(this.ctrl.value);
        if (this.ctrl.value) {
          console.log(this.ctrl.value);
          if (seted) {
            window.clearInterval(m);
          } else {
            seted = true;
            this.ctrl.setValue(this.currencyPipe.transform(this.ctrl.value, this.decimalNumber, this.symbol));
          }
        }
      }, 500);
}

有人知道我可以使用哪个HostListener来避免使用window.setInterval()。或者,如果有人知道如何解决此问题?

更新

ngOnChanges()不会每次都出现,因此所选重复问题无法解决我的问题。

4 个答案:

答案 0 :(得分:2)

我会使用整个值访问器。这就是我用于所有输入的内容。您可以这样写

@Component({
  selector: 'ks-input',
  template: `<input [(ngModel)]="value" />`,
  styleUrls: ['./whatever.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => InputComponent),
      multi: true
    }
  ]
})

export class InputComponent implements ControlValueAccessor {

  @Input('value') _value = '';
  onChange: any = () => {
  };
  onTouched: any = () => {
  };

  get value() {
    return this._value;
  }

  set value(val) {
    this._value = val;
    this.onChange(val);
    this.onTouched();
  }

  registerOnChange(fn) {
    this.onChange = fn;
  }

  registerOnTouched(fn) {
    this.onTouched = fn;
  }

  writeValue(value) {
    this.value = value;
  }
}

当您将变量传递给该组件时,它将首先通过writeValue函数,您可以在其中进行任何初始格式化。您还可以在每次值/输入ngModel变量更改时都会调用的设置值函数中执行任何操作。

答案 1 :(得分:1)

这是您可以解决此问题的方法:

<input [ngModel]="item | customCurrencyPipe:'USD':'symbol':'2.2'" name="inputField" type="text" 
(ngModelChange)="item = $event||0.00" [ngModelOptions]="{updateOn:'blur'}"/>

1)将绑定分为单向绑定和事件绑定。

2)使用事件绑定“ ngModelChange”,使用提供的输入来还原值。

3)更新'blur'的值,因此不能提供不是数字的任何文本//根据需要是可选的

4) customCurrencyPipe :这将具有货币管道的默认功能,但是如果未提供数字,则不会升级,而是返回默认值或不允许数字//根据需求

通过上述步骤,您将能够以更少的黑客攻击和有希望的解决方案获得预期的结果。

答案 2 :(得分:1)

解决方案是在 ngDoCheck() 而不是ngOnChanges()内格式化输入的值。

ngDoCheck()是一个严格的生命周期挂钩,它将在每次角度触发更改检测时运行。

A small working example显示该指令的ngDoCheck()钩总是在发生更改时被触发。


要了解为什么 ngOnChanges() 不能一直加班,为什么要使用 ngDoCheck() 来代替,

只要指令中的绑定 Input 属性发生更改,就会触发Angular更改检测。以及Angular如何检测 Input 是否已更改?它比较Simple Change对象代表 Input 的旧值和新值,如果两者之间存在差异,则Angular触发 ngOnChanges()

因此,在某些情况下您确实输入了一些内容,但比较的值却没有改变(例如,通过mutate和 Input 更改了 Object >的属性,因此Simple Change的旧值和新值实际上是相同的,因为Angular在比较引用而不是值),在这种情况下,它不会提高 ngOnChange() 钩子。


但是 ngDoChek() 有所不同。我将使用有关ngDoCheck()的这些信息from a very good article

假设我们有以下组件/指令树:

Component A
    Component B
        Component C

因此,当Angular运行更改检测时,操作顺序如下:

Checking A component:
  - update B input bindings
  - call NgDoCheck on the B component
  - update DOM interpolations for component A

 Checking B component:
    - update C input bindings
    - call NgDoCheck on the C component
    - update DOM interpolations for component B

   Checking C component:
      - update DOM interpolations for component C

如您所见,每当进行更改检测运行时,始终会调用ngDoCheck()。除此之外,在初始化组件/指令时也将调用它(重置my blitzstack example即可看到)。所以:

ngDoCheck()内设置输入值的格式将解决您的问题

答案 3 :(得分:1)

我和你有完全一样的问题。我能够使用NgControl钩子从指令访问表单控件来解决它。

我在指令构造函数中添加了NgControl:

constructor(
  private el: ElementRef, 
  private decimalPipe: DecimalPipe,
  @Self() private ngControl: NgControl) { }

这样,我可以订阅可观察到的表单控件值更改。可观察到的触发器会同时更改用户和代码,因此为避免在用户键入时进行格式化,我确认控件是原始的:

ngOnInit(): void {
  this.ngControl.valueChanges
    .subscribe(value => {
      if (this.ngControl.pristine) {
        this.el.nativeElement.value = 
          this.decimalPipe.transform(value, `1.2-2`);
      }
    });

我希望它对其他人有用。我是从https://netbasal.com/attribute-directives-angular-forms-b40503643089

这篇文章中得到的想法