npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@ngze/control-value-transformer

v1.1.0

Published

A proper way for transforming ControlValueAccessor values in two-ways

Downloads

105

Readme

codecov MIT commitizen PRs styled with prettier All Contributors ngze spectator

A proper way for transforming ControlValueAccessor values in two-ways

Have you ever needed to transform a value right before passing it to ControlValueAccessor, and transform it back to its original value type after every change? If so, you probably found that it's not straightforward.

Control Value Transformer main purpose is to simplify the way of transforming form/control values by hooking into two lifecycles of ControlValueAccessor, right before it's getting a new value, and after every value change.

Features

✅  Support two-ways transformation of ControlValueAccessor values ✅  Super easy to create and use new transformers ✅  Support both Template Drive and Reactive forms ✅  Cross-app singleton transformers

Installation

ng add @ngze/control-value-transformer

Add the ControlValueTransformerModule to your AppModule:

import { ControlValueTransformerModule } from '@ngze/control-value-transformer';

@NgModule({
  declarations: [AppComponent],
  imports: [
    FormsModule,
    ReactiveFormsModule, 
    ControlValueTransformerModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Create and Use Control Value Transformers

To create a new control value transformer all you need is to implement the Transformer interface. Here is an example of a simple transformer that transforms a number into a string via DecimalPipe just before inserting it into an input, and transforms it back to a number on every change:

import { DecimalPipe } from '@angular/common';
import { Transformer } from '@ngze/control-value-transformer';

export class NumberTransformer implements Transformer<number, string> {
  private readonly decimalPipe = new DecimalPipe('en');

  toTarget(number: number): string {
    return this.decimalPipe.transform(number);
  }

  toSource(string: string): number {
    return Number(string.replace(/[^0-9 ]/g, ''));
  }
}

Now you can use it on any component that implements ControlValueAccessor and expects to receive a string as value by using the controlValueTransformer directive:

@Component({
  template: `
    <div>
      <div>You number: {{number}}</h1>
      <input [(ngModel)]="number" [controlValueTransformer]="numberTransformer" />
    <div>
  `
})
class MyComponent {
  number: number;
  numberTransformer = new NumberTransformer();
}

The same NumberTransformer can seamlessly work with FormControl as well:

@Component({
  template: `
    <div>
      <div>You number: {{numberControl.value}}</h1>
      <input [formControl]="numberControl" [controlValueTransformer]="numberTransformer" />
    <div>
  `
})
class MyComponent {
  numberControl = new FormControl();
  numberTransformer = new NumberTransformer();
}

Inputs

| @Input | Type | Description | Default | |-------------------------|--------------------------------|--------------------------------------------------------------------------------------------------|---------| | controlValueTransformer | Transformer<S, T> \| string | Control value transformer instance or its name | - | | rewriteValueOnChange | boolean | Indicates if writeValue should be called with the transformed value after each onChange call | true |

Singleton Control Value Transformers

Singleton control value transformers allow you to use a shared transformer instance cross-app. You can define it simply by decorating your class with ControlValueTransformer:

import { DecimalPipe } from '@angular/common';
import { ControlValueTransformer, Transformer } from '@ngze/control-value-transformer';

@ControlValueTransformer({
  name: 'number'
})
export class NumberTransformer implements Transformer<number, string> {
  private readonly decimalPipe = new DecimalPipe('en');

  toTarget(number: number): string {
    return this.decimalPipe.transform(number);
  }

  toSource(string: string): number {
    return Number(string.replace(/[^0-9 ]/g, ''));
  }
}

Next step is registering the control value transfomer to make it available all over the app:

import { ControlValueTransformerModule } from '@ngze/control-value-transformer';

import { NumberTransformer } from './number.transformer';

@NgModule({
  declarations: [AppComponent],
  imports: [
    FormsModule,
    ReactiveFormsModule, 
    ControlValueTransformerModule.register([NumberTransformer])
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

Now you can use the unique name (number) instead of passing transformer instance into controlValueTransformer directive:

@Component({
  template: `
    <div>
      <div>You number: {{number}}</h1>
      <input [(ngModel)]="number" [controlValueTransformer]="'number'" />
    <div>
  `
})
class MyComponent {
  number: number;
}

Using Dependencies Injection

By default, registered control value transformers can be injected as traditional providers:

@Component(...)
class MyComponent {
  constructor(private readonly numberTransformer: NumberTransformer) {}
  ...
}

Adding Injectable on the transformer class will allow you to inject any available provider:

import { Injectable, Inject, LOCALE_ID } from '@angular/core';
import { DecimalPipe } from '@angular/common';
import { ControlValueTransformer } from '@ngze/control-value-transformer';

@Injectable()
@ControlValueTransformer({
  name: 'number'
})
export class NumberTransformer implements Transformer<number, string> {
  private readonly decimalPipe = new DecimalPipe(this.localId);

  constructor(@Inject(LOCALE_ID) private readonly localId: string) {}

  toTarget(number: number): string {
    return this.decimalPipe.transform(number);
  }

  toSource(string: string): number {
    return Number(string.replace(/[^0-9 ]/g, ''));
  }
}

Contributors ✨

Thanks goes to these wonderful people (emoji key):

This project follows the all-contributors specification. Contributions of any kind welcome!