Skip to content

Commit

Permalink
docs: ✏️ write readme
Browse files Browse the repository at this point in the history
  • Loading branch information
ZeevKatz committed Oct 30, 2020
1 parent dc00a74 commit cfdd138
Showing 1 changed file with 191 additions and 8 deletions.
199 changes: 191 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,208 @@
[![PRs](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)]()
[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-)
[![ngze](https://img.shields.io/badge/@-ngze-383636?style=flat-square&labelColor=474768)](https://github.com/ngze/)
[![spectator](https://img.shields.io/badge/tested%20with-spectator-2196F3.svg?style=flat-square)]()

> A seamless way to transform ControlValueAccessor values in two-ways.
> 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

## Installation
  Support two-ways transformation of `ControlValueAccessor` values
<br />
&nbsp;&nbsp;Super easy to create and use new transformers
<br />
&nbsp;&nbsp;Support both Template Drive and Reactive forms
<br />
&nbsp;&nbsp;Cross-app singleton transformers

## Installation
```
# Using ng
ng add @ngze/control-value-transformer
```

Add the `ControlValueTransformerModule` to your `AppModule`:

```ts
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.
<br />
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:

```ts
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:

```ts
@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:
```ts
@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.
<br/>
You can define it simply by decorating your class with `ControlValueTransformer`:

```ts
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:

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

# Using yarn
yarn add @ngze/control-value-transformer
import { NumberTransformer } from './number.transformer';

# Using npm
npm i @ngze/control-value-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:

```ts
@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:
```ts
@Component(...)
class MyComponent {
constructor(private readonly numberTransformer: NumberTransformer) {}
...
}
```

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

```ts
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 ✨

Expand Down

0 comments on commit cfdd138

Please sign in to comment.