Skip to content

Commit

Permalink
feat(lib): support for mark* methods
Browse files Browse the repository at this point in the history
Use mark* methods to change state of a form

Closes #12
  • Loading branch information
adrianriepl committed Oct 21, 2020
1 parent 7811352 commit f622d25
Show file tree
Hide file tree
Showing 3 changed files with 291 additions and 1 deletion.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,48 @@ formsManager.patchValue('onboarding', value, options);
formsManager.setValue('onboarding', value, options);
```

- `markAllAsTouched()` - A proxy to the original `markAllAsTouched` method

```ts
formsManager.markAllAsTouched('onboarding', options);
```

- `markAsTouched()` - A proxy to the original `markAsTouched` method

```ts
formsManager.markAsTouched('onboarding', options);
```

- `markAllAsDirty()` - Marks the control and all its descendant controls as dirty

```ts
formsManager.markAllAsDirty('onboarding', options);
```

- `markAsDirty()` - A proxy to the original `markAsDirty` method

```ts
formsManager.markAsDirty('onboarding', options);
```

- `markAsPending()` - A proxy to the original `markAsPending` method

```ts
formsManager.markAsPending('onboarding', options);
```

- `markAsPristine()` - A proxy to the original `markAsPristine` method

```ts
formsManager.markAsPristine('onboarding', options);
```

- `markAsUntouched()` - A proxy to the original `markAsUntouched` method

```ts
formsManager.markAsUntouched('onboarding', options);
```

- `unsubscribe()` - Unsubscribe from the form's `valueChanges` observable (always call it on `ngOnDestroy`)

```ts
Expand Down
71 changes: 71 additions & 0 deletions projects/ngneat/forms-manager/src/lib/forms-manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1282,4 +1282,75 @@ describe('FormsManager', () => {
expect(formsManager.getControl('updateOnBlurGroup', 'name').value).toEqual('Smith');
});
});

describe('Mark*', () => {
let formsManager: NgFormsManager, userForm: FormGroup;

beforeEach(() => {
formsManager = new NgFormsManager(new NgFormsManagerConfig());

userForm = new FormGroup({
name: new FormControl(),
email: new FormControl(),
date: new FormControl(),
phone: new FormGroup({
number: new FormControl(),
prefix: new FormControl(),
}),
});

formsManager.upsert('user', userForm);
});

it('should mark control and its descendants as touched', () => {
formsManager.markAllAsTouched('user');

expect(formsManager.getControl('user').touched).toBeTrue();
expect(formsManager.getControl('user', 'email').touched).toBeTrue();
expect(formsManager.getControl('user', 'phone.number').touched).toBeTrue();
});

it('should mark control as touched', () => {
formsManager.markAsTouched('user');

expect(formsManager.getControl('user').touched).toBeTrue();
});

it('should mark control and its descendants as dirty', () => {
formsManager.markAllAsDirty('user');

expect(formsManager.getControl('user').dirty).toBeTrue();
expect(formsManager.getControl('user', 'email').dirty).toBeTrue();
expect(formsManager.getControl('user', 'phone.number').dirty).toBeTrue();
});

it('should mark control as dirty', () => {
formsManager.markAsDirty('user');

expect(formsManager.getControl('user').dirty).toBeTrue();
});

it('should mark control as pending', () => {
formsManager.markAsPending('user');

expect(formsManager.getControl('user').pending).toBeTrue();
});

it('should mark control as pristine', () => {
formsManager.markAsPristine('user');

expect(formsManager.getControl('user').pristine).toBeTrue();
});

it('should mark control as untouched', () => {
formsManager.markAsUntouched('user');

expect(formsManager.getControl('user').untouched).toBeTrue();
});

afterEach(() => {
formsManager.unsubscribe();
formsManager = null;
});
});
});
179 changes: 178 additions & 1 deletion projects/ngneat/forms-manager/src/lib/forms-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Inject, Injectable, Optional } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms';
import { AbstractControl, FormGroup, FormArray } from '@angular/forms';
import { coerceArray, filterControlKeys, filterNil, isBrowser, mergeDeep } from './utils';
import { EMPTY, merge, Observable, Subject, Subscription, timer } from 'rxjs';
import { debounce, distinctUntilChanged, filter, map, mapTo, tap } from 'rxjs/operators';
Expand Down Expand Up @@ -279,6 +279,163 @@ export class NgFormsManager<FormsState = any> {
this.initialValues$$.set(name, value);
}

/**
*
* @example
*
* A proxy to the original `markAllAsTouched` method
*
* manager.markAllAsTouched('login');
*
*/
markAllAsTouched(name: keyof FormsState): void {
if (this.instances$$.has(name)) {
this.instances$$.get(name).markAllAsTouched();

this.updateStore(name, this.instances$$.get(name));
}
}

/**
*
* @example
*
* A proxy to the original `markAsTouched` method
*
* manager.markAsTouched('login');
*
*/
markAsTouched(
name: keyof FormsState,
options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}
): void {
if (this.instances$$.has(name)) {
this.instances$$.get(name).markAsTouched(options);

this.updateStore(name, this.instances$$.get(name));
}
}

/**
*
* @example
*
* Marks the control and all its descendant controls as dirty.
*
* manager.markAllAsDirty('login');
*
*/
markAllAsDirty(
name: keyof FormsState,
options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}
): void {
if (this.instances$$.has(name)) {
let control = this.instances$$.get(name);

this.markDescendantsAsDirty(control, options);

this.updateStore(name, control);
}
}

/**
*
* @example
*
* A proxy to the original `markAsDirty` method
*
* manager.markAsDirty('login');
*
*/
markAsDirty(
name: keyof FormsState,
options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}
): void {
if (this.instances$$.has(name)) {
this.instances$$.get(name).markAsDirty(options);

this.updateStore(name, this.instances$$.get(name));
}
}

/**
*
* @example
*
* A proxy to the original `markAsPending` method
*
* manager.markAsPending('login');
*
*/
markAsPending(
name: keyof FormsState,
options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}
): void {
if (this.instances$$.has(name)) {
this.instances$$.get(name).markAsPending(options);

this.updateStore(name, this.instances$$.get(name));
}
}

/**
*
* @example
*
* A proxy to the original `markAsPristine` method
*
* manager.markAsPristine('login');
*
*/
markAsPristine(
name: keyof FormsState,
options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}
): void {
if (this.instances$$.has(name)) {
this.instances$$.get(name).markAsPristine(options);

this.updateStore(name, this.instances$$.get(name));
}
}

/**
*
* @example
*
* A proxy to the original `markAsUntouched` method
*
* manager.markAsUntouched('login');
*
*/
markAsUntouched(
name: keyof FormsState,
options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}
): void {
if (this.instances$$.has(name)) {
this.instances$$.get(name).markAsUntouched(options);

this.updateStore(name, this.instances$$.get(name));
}
}

/**
*
* @example
Expand Down Expand Up @@ -462,4 +619,24 @@ export class NgFormsManager<FormsState = any> {
private removeInitialValue(name: FormKeys<FormsState>) {
coerceArray(name).forEach(name => this.initialValues$$.delete(name));
}

private markDescendantsAsDirty(
control: AbstractControl,
options?: {
onlySelf?: boolean;
emitEvent?: boolean;
}
) {
control.markAsDirty(options);

if (control instanceof FormGroup || control instanceof FormArray) {
Object.values(control.controls).forEach((control: AbstractControl) => {
control.markAsDirty(options);

if ((control as FormGroup | FormArray).controls) {
this.markDescendantsAsDirty(control, options);
}
});
}
}
}

0 comments on commit f622d25

Please sign in to comment.