ngneat / dirty-check-forms Goto Github PK
View Code? Open in Web Editor NEW🐬Detect Unsaved Changes in Angular Forms
Home Page: https://netbasal.com/detect-unsaved-changes-in-angular-forms-75fd8f5f1fa6
License: MIT License
🐬Detect Unsaved Changes in Angular Forms
Home Page: https://netbasal.com/detect-unsaved-changes-in-angular-forms-75fd8f5f1fa6
License: MIT License
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
Angular version: X.Y.Z
Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: XX
- Platform:
Others:
[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
The subscription to the browser's beforeunload
event does not seem to be unsubscribed after the user navigates outside the page, opening the modal when closing the browser's tab even when the user is not in the page that has the guard.
The modal should not appear if the user is not even in the page that has the guard.
Angular version: 9.1.0
Browser:
- [x] Chrome (desktop) version 87
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: 12.18.0
- Platform: Windows
Others:
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[X] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
When using the library with angular 12, I get an error during npm i
that there is a discrepancy between conflicting versions of tslib
. This library requires tslib@"^1.10.0"
whereas angular requires tslib@"^2.3.0"
.
Library should be compatible and install with recent versions of angular.
npm i @angular/common @angular/core tslib @ngneat/dirty-check-forms
Motivation is self-explanatory; I want to use this library with angular 12.
Angular version: X.Y.Z
Browser:
- [X] Chrome (desktop) version XX
- [X] Chrome (Android) version XX
- [X] Chrome (iOS) version XX
- [X] Firefox version XX
- [X] Safari (desktop) version XX
- [X] Safari (iOS) version XX
- [X] IE version XX
- [X] Edge version XX
For Tooling issues:
- Node version: v14.18.1
- Platform: Windows 10 x64
Others:
n/a
After installing this library and running the codebase, start getting this error.
Cannot read property 'pipe' of undefined at dirtyCheck (ngneat-dirty-check-forms.js:88)
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ X ] Bug report
[ ] Performance issue
[ X ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
I would like to use @ngneat/dirty-check-forms
in stackblitz to reproduce an issue but it seems not compatible...
To work ;)
Create a new Angular stackblitz and add the library
First of all, thanks for the lib!
But I use it with NGRX and with Containers/Presentational (I call them Meat and Skin) components, and things get complicated. I wonder if there is an easier way, or do I use it right?
Here's the code:
const routes: Routes = [
{
path: "",
component: ComponentSidenav,
children: [
...
{
path: "edit/:id",
component: CompanyEditComponent,
canDeactivate: [FormDirtyGuard],
resolve: {
company: CompanyResolver
}
}
]
}
];
Container:
export class CompanyEditComponent implements DirtyComponent {
...
readonly savedSuccessfully$ = this.stateSvc.saveSuccessful$;
isDirty$: Observable<boolean> | boolean | (() => boolean);
constructor(private stateSvc: CompaniesStateService) {
this.isDirty$ = this.savedSuccessfully$.pipe(
withLatestFrom(this.frmIsDirty.asObservable()),
map(([saved, dirty]) => {
// when data is saved then we don't care if form is dirty or not
return saved ? !saved : dirty;
})
);
}
setFormDirty(value: boolean) {
this.frmIsDirty.next(value);
}
private frmIsDirty = new BehaviorSubject<boolean>(false);
}
Presentation:
@Component({
selector: "ilg-company-edit",
templateUrl: "./company-edit-form.component.html",
styleUrls: ["./company-edit-form.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CompanyEditFormComponent extends IlgDirtyPresentationBase<object, MmlCompany> implements OnInit, OnDestroy {
@Input() company?: MmlCompany;
get form(): FormGroup<any> {
return this.frm;
}
get sourceEntity(): MmlCompany | undefined {
return this.company;
}
frm = this.fb.group<CompanyForm>({...});
constructor(private fb: NonNullableFormBuilder, private route: ActivatedRoute) {
super();
}
override ngOnInit(): void {
super.ngOnInit();
...
// this will have a value 100% because of the data resolver
if (this.company && this.company.id) {
this.frm.patchValue(this.company);
}
}
protected createEntityFromFormValue(frmVal: any): MmlCompany | undefined {
/*
*
* CAREFUL WITH THIS FUNCTION => if any error occurred YOU WON'T SEE IT!
* Use try {} catch {}
*
*/
if (areAllPropsFalsy(frmVal)) {
// if all props are falsy ==> return undefined
return undefined;
}
return new MmlCompany(
frmVal.name ?? "",
frmVal.shortName ?? "",
frmVal.phone ?? "",
frmVal.email ?? "",
this.company ? this.company.printingMml : true,
frmVal.licenseNumber,
frmVal.licenseExpDate,
this.company ? this.company.id : undefined,
frmVal.comment
);
}
}
And here's the common class to implement dirty checking for any of Presentational form component:
export abstract class IlgDirtyPresentationBase<T, R> implements OnInit, OnDestroy {
@Output() formIsDirty = new EventEmitter<boolean>();
abstract form: FormGroup;
abstract sourceEntity: R | undefined;
protected subscriptions = new Subscription();
isDirty$?: Observable<boolean>;
protected abstract createEntityFromFormValue(frmVal: T): R | undefined;
ngOnDestroy() {
this.subscriptions.unsubscribe();
}
ngOnInit(): void {
this.isDirty$ = this.form.valueChanges.pipe(this.checkIsDirty(this.sourceEntity, this.createEntityFromFormValue.bind(this))); // bind() IS IMPORTANT HERE!
this.subscriptions.add(
//
// ===> this subscription MUST BE in ngOnInit !!!
//
this.isDirty$.subscribe((val) => this.formIsDirty.emit(val))
);
}
private checkIsDirty<T, R>(sourceEntity: R | undefined, createEntityFromFormValue: (frmVal: T) => R): OperatorFunction<T, boolean> {
function wrapUserFunction(frmVal: T) {
try {
return createEntityFromFormValue(frmVal);
} catch (e) {
console.error(`createCompanyFromValue exception: ${e}`);
// return {} as R;
throw e;
}
}
return pipe(
debounceTime(400),
distinctUntilChanged(),
map(wrapUserFunction),
map((frmEntity) => !deepEqualRelaxed(sourceEntity, frmEntity)),
startWith(false),
shareReplay()
);
}
I did not find a way to adopt easily dirty-check-forms lib for actual checking. Store shouldn't be present in Presentational components.
[x] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[x] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
dirtyCheck
operator uses global window
object.
dirty-check-forms/libs/dirty-check-forms/src/lib/dirty-check.ts
Lines 62 to 64 in 944447a
I think, It's better to pass window
option in config.
Current behavior leads to restrictions on the use of SSR. Also it's impossible to apply dirtyCheck
without beforeunload
event.
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
Angular version: X.Y.Z
Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: XX
- Platform:
Others:
I have a dropdown that get's pre-populated with default first value from the options, when the form is created it's empty all values are null but then inputs$ that I am using from ngx-sub-form on subscribe are populated with the dropdown values so the form becomes pristine:false and the form is marked as dirty, I am not clear how to fix it. Thank you
initControlWithOptions() {
if (this.autoDisplayFirst && this.options && this.options.length > 0 && this.control) {
const firstOptionValue = this.optionValue ? this.options[0][this.optionValue] : this.options[0];
this.control.patchValue(firstOptionValue, { emitEvent: true });
}
}
Angular version: 17
For Tooling issues:
- Node version: v18.17.0
- Platform: Mac
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[X] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
When guard is put on a route and a component without isDirty$ implementation the guard triggers the confirmChanges method. I'm not sure if this is a desired behavior.
Put the Guard on a route with a component that doesn't implement the isDirty$ property.
It would make sense to not have the confirmChanges triggers.
I can put a proposal if needed.
Best regards,
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ x] Other... Please describe: problem with a project
HI!
First : sorry to my level in English writing
In a project, I've got a form with the save button have the property [disabled] ="!(isDirty$ | async)" in the component.
I call him in a other component with a Selector my-custom-form with [(isDirty$)] ="isDirty$" and (formChange)="formChange($event)". In that component, I call another component which refers to a property of my json object :
data: {
property: {
id: 0,
name: 'foo',
order: 45,
propertyDetails: {
[0]
...
[n]
}
}
}
I can have the button on enable when I change Foo to Foo2 in the input mais the disabled when remove the character 2. In my form, I have the propertyDetails in anothers inputs, but when I make some change, nothing happens.
I could see, all the data I change and enabled the save button are in the model of the form.
I want to know how make the detection on the propertyDetails in my form.
Could you help me please ?
I would be most grateful in the world 😭😭😭😭
Angular version: 10.2.1
Browser:
- [ x] Chrome (desktop) version XX (dépend of the client)
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: 16.13.1
- Platform: windows
Others:
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[X] Support request
[ ] Other... Please describe:
just followed the instructions as described in the documentation.
dev
Angular version: 7.0.3
Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [X] Edge Version 83.0.478.56 (Official build) (64-bit)
[X] Regression (a behavior that used to work and stopped working in a new release)
When upgrading from 3.0.2 to version 3.0.3, I have an error in my Jest tests related to components using the dirty-check-library
.
In fact, now the library is using lodash-es
that is exposing esm
module not recognized by Jest.
Using a new MINOR version instead of the PATCH version when upgrading a library.
[ ] Regression (a behavior that used to work and stopped working in a new release)
[X] Bug report
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
When I leave the page, I got an error:
Uncaught (in promise): TypeError: Class constructor DirtyCheckGuard cannot be invoked without 'new'\nTypeError: Class constructor DirtyCheckGuard cannot be invoked without 'new'\n at new DirtyGuard (https://localhost:5300/src_app_layout_products_products_module_ts.js:23:19)\n at Object.DirtyGuard_Factory [as factory] (https://localhost:5300/src_app_layout_products_products_module_ts.js:29:12)\n at R3Injector.hydrate (https://localhost:5300/vendor.js:56921:29)\n at R3Injector.get (https://localhost:5300/vendor.js:56822:23)\n at R3Injector.get (https://localhost:5300/vendor.js:56831:27)\n at R3Injector.get (https://localhost:5300/vendor.js:56831:27)\n at getTokenOrFunctionIdentity (https://localhost:5300/vendor.js:134858:27)\n at https://localhost:5300/vendor.js:135152:19\n at Array.map ()\n at runCanDeactivate (https://localhost:5300/vendor.js:135150:50)
Angular version: 15.0.2
Browser:
- [X] Chrome (desktop) version 107.0.5304.107
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: 18
- Platform: Windows 11
Others:
[ ] Regression (a behavior that used to work and stopped working in a new release)
[X ] Bug report
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
yarn add @ngneat/dirty-check-forms
yarn add @ngneat/dirty-check-forms should install the package
yarn install command gives error without installation
error An unexpected error occurred: "EPERM: operation not permitted, lstat '..\node_modules\@schematics\update\node_modules\npm-package-arg\node_modules'"
Angular version: X.Y.Z
Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: XX v13.3.0
- npm version 6.13.1
- Platform: Windows 10
Others:
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[x] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
DirtyCheckGuard does not work with lazy-loaded components.
DirtyCheckGuard should work with lazy loaded components.
I followed the instructions to set up a DirtyCheckGuard on "In-App navigation", but the instructions require that the component route not be a lazy loaded route. For example, while the example setup on the home page of this repo works, the following will not work:
const routes: Routes = [
{
path: 'settings',
canDeactivate: [DirtyCheckGuard],
loadChildren: () =>
import('./settings.module').then((m) => m.SettingsPageModule)
},
];
If I were more intelligent I would know how to make this work myself, but alas, I am not. Or maybe I missed something obvious.
To be able to keep my routes "lazy-loaded" as well as use the DirtyCheckGuard
Angular version: 14.2.0
Browser:
- [x] Chrome (desktop) version 105
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: v16.13.1
- Platform: Windows
Others:
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[X] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
When using this library with Angular 13, I got this message:
Processing legacy "View Engine" libraries:
- @ngneat/dirty-check-forms [es2015/esm2015] (https://github.com/ngneat/dirty-check-forms)
- @ngneat/dirty-check-forms [module/esm5] (https://github.com/ngneat/dirty-check-forms)
- @ngneat/dirty-check-forms [main/umd] (https://github.com/ngneat/dirty-check-forms)
Encourage the library authors to publish an Ivy distribution.
So I am encouraging it :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.