Пользовательские директивы реактивной формы не запускаются OnInit или когда скрытый ввод отображается *ngIf

Используя реактивные формы в Angular, я создал две директивы: одну, которая преобразует значения из центов в доллары путем деления на 100, а другую, которая преобразует доллары в центы путем умножения на 100. Это работает, когда я вручную устанавливаю элементы управления формой, но не получается. применил OnInit, и он не применяется, когда ввод формы отображается, когда он скрыт за *ngIf.

Я создал stackblitz с примером. В OnInit должно отображаться $12,345.50, но вместо этого отображается $12,34550.00 и одно и то же значение, когда отображается поле формы, пока они не будут установлены вручную с помощью кнопок. Пример приведен в Angular v15, но я использую v18, если это помогает с решением, но могу воспроизвести его аналогичным образом в любом из них.

Есть ли способ запустить директивы OnInit и при отображении ввода? Или мне следует реализовать это по-другому?

«Интерфейс OnInit имеет метод-перехватчик с именем ngOnInit(). Если вы реализуете этот метод в своем классе компонента или директивы, Angular вызывает его вскоре после первой проверки входных свойств для этого компонента или директивы». Итак, в вашей директиве реализуйте OnInit, и они будут вызваны в это время.

D A 11.07.2024 08:47
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
2
1
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мы можем получить доступ к директиве NgControl и напрямую исправить преобразованное значение при первой загрузке.

Также не используйте *ngIf при работе со скрытыми формами. Из-за этого элементы управления не работают должным образом, поскольку они удалены из DOM; вместо этого всегда используйте атрибут [hidden]:

import { AfterContentInit, Directive, Input, inject } from '@angular/core';
import {
  DefaultValueAccessor,
  FormControlName,
  NgControl,
} from '@angular/forms';
import {
  maskitoNumberOptionsGenerator,
  maskitoParseNumber,
} from '@maskito/kit';

export const dollarMask = maskitoNumberOptionsGenerator({
  min: 0,
  // Maximum to avoid floating point precision errors
  // which will occur when numeric values are too large
  // exceeding Number.MAX_SAFE_INTEGER
  max: 1000000000,
  precision: 2,
  decimalSeparator: '.',
  decimalZeroPadding: true,
  thousandSeparator: ',',
  prefix: '$',
});

@Directive({
  standalone: true,
  selector: '[maskito][toDollars]',
})
export class ToDollarsDirective {
  private readonly accessor = inject(DefaultValueAccessor, { self: true });
  private readonly formControlName = inject(NgControl, { self: true });

  ngOnInit() {
    const initialValue = this.formControlName.value;
    const dollars1 = initialValue != null ? initialValue / 100 : initialValue;
    this.formControlName.control!.patchValue(dollars1);
  }

  ngOnAfterContentInit() {
    const original = this.accessor.writeValue.bind(this.accessor);
    this.accessor.writeValue = (value: any) => {
      const dollars = value != null ? value / 100 : value;
      original(dollars);
    };
  }
}

@Directive({
  standalone: true,
  selector: '[maskito][toCents]',
})
export class ToCentsDirective {
  private readonly accessor = inject(DefaultValueAccessor, { self: true });
  private readonly formControlName = inject(NgControl, { self: true });


  ngAfterContentInit() {
    const original = this.accessor.onChange.bind(this.accessor);
    this.accessor.onChange = (value: any) => {
      const cents = maskitoParseNumber(value) * 100;
      original(cents);
    };
  }
}

Демо-версия Stackblitz

Спасибо, это было очень полезно! Я заметил, что директива toCents, похоже, влияет на проверку ввода. Можно ли что-то добавить в директиву, чтобы это не мешало проверкам?

mtpultz 12.07.2024 22:33

Другие вопросы по теме