Carlos Cifuentes
AngularJS → Angular reference

$parsers / $formatters in modern Angular

$parsers and $formatters become the two directions of a ControlValueAccessor: writeValue for model to view, and the registered onChange callback for view to model.

Before · AngularJS
app.directive('cents', function () {
  return {
    require: 'ngModel',
    link: function (scope, el, attrs, ngModel) {
      // model (cents) -> view (dollars)
      ngModel.$formatters.push(function (cents) { return (cents / 100).toFixed(2); });
      // view (dollars) -> model (cents)
      ngModel.$parsers.push(function (text) { return Math.round(parseFloat(text) * 100); });
    }
  };
});
After · Angular
@Component({
  selector: 'app-money-input',
  template: `<input #box [value]="text()" (input)="onInput(box.value)" (blur)="onTouched()" />`,
  providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MoneyInputComponent), multi: true }],
})
export class MoneyInputComponent implements ControlValueAccessor {
  text = signal('');
  private onChange: (cents: number) => void = () => {};
  onTouched: () => void = () => {};

  writeValue(cents: number | null) { this.text.set(((cents ?? 0) / 100).toFixed(2)); } // $formatters
  registerOnChange(fn: (cents: number) => void) { this.onChange = fn; }
  registerOnTouched(fn: () => void) { this.onTouched = fn; }
  onInput(text: string) { this.onChange(Math.round(parseFloat(text) * 100)); } // $parsers
}

What changes

  • $formatters logic moves to writeValue, which receives the model value and updates what the input shows.
  • $parsers logic runs on user input and passes the parsed value to the callback from registerOnChange.
  • The result is a component or directive that works with formControl, formControlName and ngModel.

Migration tip. Keep ControlValueAccessor for real custom inputs. A parser that only trims or normalizes text is simpler as a transformation applied when you read the form value.

Related

Planning a migration or a micro-frontend platform?

In a 20-minute call you describe your situation and I tell you how I'd approach it. If it isn't worth doing yet, I'll say so.

Message me on LinkedIn