Форматирование числа / валюты в угловой директиве 6 - PullRequest
0 голосов
/ 10 июля 2019

Я создал валютную директиву, которую я буду использовать в каждом элементе ввода , для которого требуется формат валюты.

Итак, у меня есть 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() не возникает каждый раз, поэтому выбранный повторяющийся вопрос не может решить мою проблему.

Ответы [ 3 ]

2 голосов
/ 17 июля 2019

Я бы использовал всю функцию доступа к значению. Вот что я использую для всех моих входов. Вы можете написать что-то вроде этого

@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, где вы можете выполнить любое начальное форматирование. вы также можете делать то, что когда-либо в функции заданного значения, которая вызывается каждый раз, когда изменяется переменная value / input ngModel.

1 голос
/ 22 июля 2019

Решением является форматирование значения ввода внутри ngDoCheck() вместо ngOnChanges().

ngDoCheck() - это гарантированный хук жизненного цикла, который будет запускаться каждый раз при изменении углового триггераобнаружение.

Небольшой рабочий пример , показывающий, что ngDoCheck() хук директивы всегда будет срабатывать при изменении.


Для понимания, почему ngOnChanges() не вызывает все время и почему вместо этого используется ngDoCheck():

Всякий раз, когда свойство привязки Input из директивы изменяется, это вызывает обнаружение изменения угла.И как Angular определяет, что это Input изменено?Он сравнивает Simple Change объект, представляющий, что Input старые и новые значения, если есть различия между ними, то угловой триггер ngOnChanges() lifeвелосипедный крючок

Таким образом, есть случай, когда вы что-то ввели, но сравниваемое значение не меняется (например, вы меняете Input на mutate и Object sсвойство, поэтому на самом деле старое и новое значение Simple Change одинаково, поскольку Angular сравнивает ссылку, а не значение), в этом случае оно не повышает ngOnChange() hook.


Но ngDoChek() - это нечто другое.Я буду использовать эту информацию из очень хорошей статьи относительно ngDoCheck():

Предположим, у нас есть следующее дерево компонентов / директив:

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().Кроме того, он также вызывается, когда компонент / директива инициализированы (сбросьте мой пример блиц-стека , чтобы увидеть это).Итак:

Форматирование значения ввода внутри ngDoCheck() решит вашу проблему

1 голос
/ 16 июля 2019

Вот что вы можете сделать, чтобы решить эту проблему:

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

1) Разделить привязку на одностороннюю привязку и привязку события.

2) С привязкой к событию "ngModelChange" восстановить значение с предоставленным вводом.

3) Обновить значение на «размытие», поэтому любой текст, который не является числом, не может быть обработан // необязательно в зависимости от требования

4) customCurrencyPipe : Это будет иметь функции по умолчанию для денежной трубы, но не будет увеличиваться, если число не предоставлено, вместо этого будет возвращено значение по умолчанию или не будет разрешено отличное от // основанное на числах по требованию

С помощью описанных выше шагов вы сможете достичь желаемых результатов с меньшими усилиями и многообещающим решением.

...