@ngneat/dirty-check-forms
Version:
Detect Unsaved Changes in Angular Forms
48 lines • 7.85 kB
JavaScript
import { FormArray, FormGroup } from '@angular/forms';
import { combineLatest, defer, fromEvent, merge, Observable, of } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, shareReplay, startWith, withLatestFrom, } from 'rxjs/operators';
import { equal as isEqual } from './is-equal';
import omit from 'lodash-es/omit';
const defaults = {
debounce: 300,
withDisabled: true,
useBeforeunloadEvent: true,
};
function getControlValue(control, withDisabled) {
if (withDisabled &&
(control instanceof FormGroup || control instanceof FormArray)) {
return control.getRawValue();
}
return control.value;
}
export function dirtyCheck(control, source, config = {}) {
const { debounce, withDisabled, useBeforeunloadEvent, excludeKeys } = {
...defaults,
...config,
};
const value = () => getControlValue(control, withDisabled);
const valueChanges$ = merge(defer(() => of(value())), control.valueChanges.pipe(debounceTime(debounce), distinctUntilChanged(), map(() => value())));
return new Observable((observer) => {
const isDirty$ = combineLatest([
source,
valueChanges$,
]).pipe(map(([a, b]) => {
if (excludeKeys) {
return !isEqual(omit(a, excludeKeys), omit(b, excludeKeys));
}
return !isEqual(a, b);
}), startWith(false), shareReplay({ bufferSize: 1, refCount: true }));
if (useBeforeunloadEvent) {
observer.add(fromEvent(window, 'beforeunload')
.pipe(withLatestFrom(isDirty$))
.subscribe(([event, isDirty]) => {
if (isDirty) {
event.preventDefault();
event.returnValue = false;
}
}));
}
return isDirty$.subscribe(observer);
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlydHktY2hlY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzL2RpcnR5LWNoZWNrLWZvcm1zL3NyYy9saWIvZGlydHktY2hlY2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFtQixTQUFTLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdkUsT0FBTyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlFLE9BQU8sRUFDTCxZQUFZLEVBQ1osb0JBQW9CLEVBQ3BCLEdBQUcsRUFDSCxXQUFXLEVBQ1gsU0FBUyxFQUNULGNBQWMsR0FDZixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFBRSxLQUFLLElBQUksT0FBTyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzlDLE9BQU8sSUFBSSxNQUFNLGdCQUFnQixDQUFDO0FBU2xDLE1BQU0sUUFBUSxHQUFxQjtJQUNqQyxRQUFRLEVBQUUsR0FBRztJQUNiLFlBQVksRUFBRSxJQUFJO0lBQ2xCLG9CQUFvQixFQUFFLElBQUk7Q0FDM0IsQ0FBQztBQUVGLFNBQVMsZUFBZSxDQUFDLE9BQXdCLEVBQUUsWUFBcUI7SUFDdEUsSUFDRSxZQUFZO1FBQ1osQ0FBQyxPQUFPLFlBQVksU0FBUyxJQUFJLE9BQU8sWUFBWSxTQUFTLENBQUMsRUFDOUQ7UUFDQSxPQUFPLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQztLQUM5QjtJQUNELE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FBQztBQUN2QixDQUFDO0FBRUQsTUFBTSxVQUFVLFVBQVUsQ0FNeEIsT0FBd0IsRUFDeEIsTUFBcUIsRUFDckIsU0FBaUIsRUFBWTtJQUU3QixNQUFNLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxXQUFXLEVBQUUsR0FBRztRQUNwRSxHQUFHLFFBQVE7UUFDWCxHQUFHLE1BQU07S0FDVixDQUFDO0lBQ0YsTUFBTSxLQUFLLEdBQUcsR0FBRyxFQUFFLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQztJQUMzRCxNQUFNLGFBQWEsR0FBRyxLQUFLLENBQ3pCLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxFQUN4QixPQUFPLENBQUMsWUFBWSxDQUFDLElBQUksQ0FDdkIsWUFBWSxDQUFDLFFBQVEsQ0FBQyxFQUN0QixvQkFBb0IsRUFBRSxFQUN0QixHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FDbkIsQ0FDRixDQUFDO0lBRUYsT0FBTyxJQUFJLFVBQVUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFO1FBQ2pDLE1BQU0sUUFBUSxHQUF3QixhQUFhLENBQUM7WUFDbEQsTUFBTTtZQUNOLGFBQWE7U0FDZCxDQUFDLENBQUMsSUFBSSxDQUNMLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUU7WUFDYixJQUFJLFdBQVcsRUFBRTtnQkFDZixPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsV0FBVyxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUMsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO2FBQzdEO1lBRUQsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDeEIsQ0FBQyxDQUFDLEVBQ0YsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUNoQixXQUFXLENBQUMsRUFBRSxVQUFVLEVBQUUsQ0FBQyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUMvQyxDQUFDO1FBRUYsSUFBSSxvQkFBb0IsRUFBRTtZQUN4QixRQUFRLENBQUMsR0FBRyxDQUNWLFNBQVMsQ0FBQyxNQUFNLEVBQUUsY0FBYyxDQUFDO2lCQUM5QixJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxDQUFDO2lCQUM5QixTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFO2dCQUM5QixJQUFJLE9BQU8sRUFBRTtvQkFDWCxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7b0JBQ3ZCLEtBQUssQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO2lCQUMzQjtZQUNILENBQUMsQ0FBQyxDQUNMLENBQUM7U0FDSDtRQUVELE9BQU8sUUFBUSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN0QyxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1BcnJheSwgRm9ybUdyb3VwIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgY29tYmluZUxhdGVzdCwgZGVmZXIsIGZyb21FdmVudCwgbWVyZ2UsIE9ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBkZWJvdW5jZVRpbWUsXG4gIGRpc3RpbmN0VW50aWxDaGFuZ2VkLFxuICBtYXAsXG4gIHNoYXJlUmVwbGF5LFxuICBzdGFydFdpdGgsXG4gIHdpdGhMYXRlc3RGcm9tLFxufSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBlcXVhbCBhcyBpc0VxdWFsIH0gZnJvbSAnLi9pcy1lcXVhbCc7XG5pbXBvcnQgb21pdCBmcm9tICdsb2Rhc2gtZXMvb21pdCc7XG5cbmludGVyZmFjZSBEaXJ0eUNoZWNrQ29uZmlnPFUgPSB1bmtub3duPiB7XG4gIGRlYm91bmNlPzogbnVtYmVyO1xuICB3aXRoRGlzYWJsZWQ/OiBib29sZWFuO1xuICB1c2VCZWZvcmV1bmxvYWRFdmVudD86IGJvb2xlYW47XG4gIGV4Y2x1ZGVLZXlzPzogQXJyYXk8a2V5b2YgVT47XG59XG5cbmNvbnN0IGRlZmF1bHRzOiBEaXJ0eUNoZWNrQ29uZmlnID0ge1xuICBkZWJvdW5jZTogMzAwLFxuICB3aXRoRGlzYWJsZWQ6IHRydWUsXG4gIHVzZUJlZm9yZXVubG9hZEV2ZW50OiB0cnVlLFxufTtcblxuZnVuY3Rpb24gZ2V0Q29udHJvbFZhbHVlKGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCwgd2l0aERpc2FibGVkOiBib29sZWFuKSB7XG4gIGlmIChcbiAgICB3aXRoRGlzYWJsZWQgJiZcbiAgICAoY29udHJvbCBpbnN0YW5jZW9mIEZvcm1Hcm91cCB8fCBjb250cm9sIGluc3RhbmNlb2YgRm9ybUFycmF5KVxuICApIHtcbiAgICByZXR1cm4gY29udHJvbC5nZXRSYXdWYWx1ZSgpO1xuICB9XG4gIHJldHVybiBjb250cm9sLnZhbHVlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZGlydHlDaGVjazxcbiAgVSxcbiAgQ29uZmlnIGV4dGVuZHMgVSBleHRlbmRzIG9iamVjdFxuICAgID8gRGlydHlDaGVja0NvbmZpZzxVPlxuICAgIDogT21pdDxEaXJ0eUNoZWNrQ29uZmlnPFU+LCAnZXhjbHVkZUtleXMnPlxuPihcbiAgY29udHJvbDogQWJzdHJhY3RDb250cm9sLFxuICBzb3VyY2U6IE9ic2VydmFibGU8VT4sXG4gIGNvbmZpZzogQ29uZmlnID0ge30gYXMgQ29uZmlnXG4pOiBPYnNlcnZhYmxlPGJvb2xlYW4+IHtcbiAgY29uc3QgeyBkZWJvdW5jZSwgd2l0aERpc2FibGVkLCB1c2VCZWZvcmV1bmxvYWRFdmVudCwgZXhjbHVkZUtleXMgfSA9IHtcbiAgICAuLi5kZWZhdWx0cyxcbiAgICAuLi5jb25maWcsXG4gIH07XG4gIGNvbnN0IHZhbHVlID0gKCkgPT4gZ2V0Q29udHJvbFZhbHVlKGNvbnRyb2wsIHdpdGhEaXNhYmxlZCk7XG4gIGNvbnN0IHZhbHVlQ2hhbmdlcyQgPSBtZXJnZShcbiAgICBkZWZlcigoKSA9PiBvZih2YWx1ZSgpKSksXG4gICAgY29udHJvbC52YWx1ZUNoYW5nZXMucGlwZShcbiAgICAgIGRlYm91bmNlVGltZShkZWJvdW5jZSksXG4gICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpLFxuICAgICAgbWFwKCgpID0+IHZhbHVlKCkpXG4gICAgKVxuICApO1xuXG4gIHJldHVybiBuZXcgT2JzZXJ2YWJsZSgob2JzZXJ2ZXIpID0+IHtcbiAgICBjb25zdCBpc0RpcnR5JDogT2JzZXJ2YWJsZTxib29sZWFuPiA9IGNvbWJpbmVMYXRlc3QoW1xuICAgICAgc291cmNlLFxuICAgICAgdmFsdWVDaGFuZ2VzJCxcbiAgICBdKS5waXBlKFxuICAgICAgbWFwKChbYSwgYl0pID0+IHtcbiAgICAgICAgaWYgKGV4Y2x1ZGVLZXlzKSB7XG4gICAgICAgICAgcmV0dXJuICFpc0VxdWFsKG9taXQoYSwgZXhjbHVkZUtleXMpLCBvbWl0KGIsIGV4Y2x1ZGVLZXlzKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gIWlzRXF1YWwoYSwgYik7XG4gICAgICB9KSxcbiAgICAgIHN0YXJ0V2l0aChmYWxzZSksXG4gICAgICBzaGFyZVJlcGxheSh7IGJ1ZmZlclNpemU6IDEsIHJlZkNvdW50OiB0cnVlIH0pXG4gICAgKTtcblxuICAgIGlmICh1c2VCZWZvcmV1bmxvYWRFdmVudCkge1xuICAgICAgb2JzZXJ2ZXIuYWRkKFxuICAgICAgICBmcm9tRXZlbnQod2luZG93LCAnYmVmb3JldW5sb2FkJylcbiAgICAgICAgICAucGlwZSh3aXRoTGF0ZXN0RnJvbShpc0RpcnR5JCkpXG4gICAgICAgICAgLnN1YnNjcmliZSgoW2V2ZW50LCBpc0RpcnR5XSkgPT4ge1xuICAgICAgICAgICAgaWYgKGlzRGlydHkpIHtcbiAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgZXZlbnQucmV0dXJuVmFsdWUgPSBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gaXNEaXJ0eSQuc3Vic2NyaWJlKG9ic2VydmVyKTtcbiAgfSk7XG59XG4iXX0=