ngneat / reactive-forms Goto Github PK
View Code? Open in Web Editor NEW(Angular Reactive) Forms with Benefits ๐
Home Page: https://www.netbasal.com
(Angular Reactive) Forms with Benefits ๐
Home Page: https://www.netbasal.com
[ ] 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:
Setting an error to a control using .setErrors()
does not trigger a new value to be emitted from .errors$
.
calling .setErrors()
should trigger .errors$
to emit
We're calling .setErrors()
based on a response from the API. Currently, this lib only checks for changes in errors directly after valueChanges, but since the API call is async, valueChanges is never triggered.
Angular version: 9.1.9
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:
[ X ] Bug report
After a successful install the migration command ng g @ngneat/reactive-forms:migrate
is not working:
An unhandled exception occurred: Cannot find module '@phenomnomnominal/tsquery'
Require stack:
- /Users/person/app/node_modules/@ngneat/reactive-forms/schematics/migrate/index.js
- /Users/person/app/node_modules/@angular/cli/node_modules/@angular-devkit/schematics/tools/export-ref.js
- /Users/person/app/node_modules/@angular/cli/node_modules/@angular-devkit/schematics/tools/index.js
- /Users/person/app/node_modules/@angular/cli/utilities/json-schema.js
- /Users/person/app/node_modules/@angular/cli/models/command-runner.js
- /Users/person/app/node_modules/@angular/cli/lib/cli/index.js
- /Users/person/.nvm/versions/node/v13.8.0/lib/node_modules/@angular/cli/lib/init.js
- /Users/person/.nvm/versions/node/v13.8.0/lib/node_modules/@angular/cli/bin/ng
See "/private/var/folders/jd/4qd93gyj3c9_18z3_yvy3gl80000gn/T/ng-Z1HDXJ/angular-errors.log" for further details.
The path is tiny bit changed but only in terms of User name and app folder name. I checked most of those paths and they have the appropriate files.
It should run migration command successfully.
Can't offer repo for reproduction at this point but can try if it will be useful.
Angular version: 11.0.1
For Tooling issues:
- Node version: 13.8.0 (through NVM)
- Platform: Mac
Others:
Part of app contains Angular Element. Could it be relevant?
[ ] 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:
Following compilation error appears when pushing to typed FormArray
Argument of type 'FormGroup<Element, any>' is not assignable to parameter of type 'AbstractControl<Element>'.
Types of property 'get' are incompatible.
Type '{ <K1 extends "minimum" | "maximum">(path?: [K1] | undefined): AbstractControl<Element[K1]>; <K1 extends "minimum" | "maximum", K2 extends keyof Element[K1]>(path?: [...] | undefined): AbstractControl<...>; <K1 extends "minimum" | "maximum", K2 extends keyof Element[K1], K3 extends keyof Element[K1][K2]>(path?: [......' is not assignable to type '(path: string | (string | number)[]) => AbstractControl | null'.
Types of parameters 'path' and 'path' are incompatible.
Type 'string | (string | number)[]' is not assignable to type '[any] | undefined'.
Type 'string' is not assignable to type '[any] | undefined'.ts(2345)
Consider following example:
import { Component } from "@angular/core";
import {
AbstractControl,
FormArray,
FormBuilder,
FormControl,
FormGroup
} from "@ngneat/reactive-forms";
interface Element {
minimum: string;
maximum: string;
}
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
elementsForm: FormArray<Element>;
constructor(private formBuilder: FormBuilder) {
this.elementsForm = formBuilder.array([]);
}
addElement() {
const element = this.formBuilder.group<Element>({
minimum: '',
maximum: ''
});
this.elementsForm.push(element);
}
}
this.elementsForm.push(element)
causes described error.
I applied following fix:
this.elementsForm.push(element as AbstractControl<Element>)
since push method accepts AbstractControl, but FormGroup extends NgFormGroup which doesn't accept generic types.
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:
Hi everyone!
I'm using the persist
method to store the FormGroup
to the sessionStorage, but it doesn't store disabled controls (I don't know if there is a reason for that).
Right now, I found a workaround by creating my own class implementing the PersistManager
interface but I was wondering if there was any drawbacks to use value$
instead of valueChanges
in the line below?
This would allow to integrate the disabled controls when we use the persist
method.
Thanks!
In one of my project, I performed the migration from Angular 9 to 10.
I saw some failing tests related to the forms validation.
I figured that using this project was the root cause.
Using Angular imports instead (for the FormGroup
and FormControl
) fixed my issue.
[ ] 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 validators are not working (native and custom).
An empty string value in a control with a required validator or a custom one (actually in this reproduction it was a validator that check if the value is null
, undefined
or ''
) should be considered as an error.
In this reproduction, there is two identical forms that should invalidate the form right from the initialisation.
One is based on classes from Angular and the second from ngneat.
Angular is working as expected.
Ngneat is telling me that my form is valid.
I can see that the custom validator log is not trigger when the value change in the ngneat form.
https://ngneat-testing-issue.stackblitz.io/
It should work like Angular.
Angular version: 11.0.8
Browser:
- [x] Chrome (desktop) version 89.0.4389.128
[ ] 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:
Fails to compile with error: Type 'AbstractControl' is missing the following properties from type 'AbstractControl<IForm, any>': touch$, dirty$, disabled$, enabled$, status$
This seems to be touched on in #26 , #87 , #101 , #65 . However, I am on the latest version and this still happens, even after trying solutions suggested on these tickets.
Apologies if I'm just using incorrect syntax or interfaces, I'm quite new to reactive forms :) .
Compiles with no issues (which it does with strict mode off).
See line 27 of app.component.ts for error. It seems to be compiling on this site regardless of tsconfig, but the error it shows on the line is what is blocking me in any other environment.
https://codesandbox.io/s/brave-silence-40z69?file=/src/app/app.component.ts
Non-strict mode without any errors:
https://codesandbox.io/s/kind-mayer-s0b3s?file=/src/app/app.component.ts
Stackblitz wasn't consistently loading the dependency correctly.
I'm trying to perform cross validation on multiple form inputs as the minimal example shows.
I can, if necessary, do this without ValidatorFn's but working validation within the reactive form would be highly preferable to custom code on form submission.
Angular version: 12.2.0 for minimal example, 11.2.6 for production code I'm writing.
Browser **unsure if relevant?**:
- [X] Chrome (desktop) version 92
From short initial investigation it seems like this typing:
Needs to be changed to be recursive in such a way that it can aggregate the different Validators that are used on a FormControl
At the moment, an error is thrown for the following:
email: new FormControl('', [Validators.required, Validators.email])
Which states that {email: true}
is not assignable to {required: true}
.
I believe this needs a slight change to how the object type is built.
[ ] 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 running unit tests in a jest environment they fail when using the required validator on a FormControl because it always returns true even when the value is invalid. Using the FormControl from the @angular/forms
package works fine.
This only happens in a jest environment, the actual functionality in a browser or when using jasmine for the unit tests works as expected. I'm sorry if I've raised this bug in the wrong place, it could be a problem with jest or jsdom. I'm going to keep trying to debug and see if I can find out the reason why.
The following issue might be relevant from what I found when searching the closed issues:
#86
When the FormControl is invalid
then it should return false
when checking the valid
property for unit tests running with jest.
I've attached a zip file to this ticket with a sample angular project that shows the tests passing when using jasmine and failing when using jest.
To run the jasmine unit tests that work use this command:
npm run test
To run the jest unit tests that fail use this command:
npm run test:jest
Unit tests pass when using jest and this project.
Angular version: 11.2.13
Browser:
- [x] TS Jest version 26.5.6 (jsdom 16.5.3)
For Tooling issues:
- Node version: v14.9.0
- Platform: Mac
Hi,
I see the following in the docs
this.value$.pipe(diff()).subscribe((value) => {
// value is emitted only if it has been changed, and only the changed parts.
})
Where is the diff() function imported from? I can't seem to find a module that exports such a function.
Thanks
[X] Support request
A FormGroup
's value$
observable emits a ControlsValue<T>
instead of a T
.
I want to actually get a value of type T
so that I can do this:
this.formGroup.value$.pipe(
takeUntil(this.unsubscribe$),
).subscribe(x => {
this.onTouch?.()
this.onModelChange?.(x)
})
That doesn't work though because x
there isn't actually of type T
I'm doing nested forms, and so when this form changes, I pass the value up to the parent's control.
Angular version: 12.1.2
Browser:
- [ X] Chrome (desktop) version XX
For Tooling issues:
- Node version: v12.19.0
- Platform: Windows 10
Convert import from '@angular/forms'
to @ngneat/reactive-forms
[X] Support request
I'm using this with nested components where each child component is a CVA that has its own FormGroup. Right now I'm doing something like this, which just feels wrong.
@ViewChild(DetailGeneralComponent) private general!: DetailGeneralComponent
ngOnInit(): void {
this.formGroup = this.fb.group({
general: this.fb.group<IDetailGeneralForm>({
manager: undefined,
delegate: undefined,
linkUrl: undefined,
linkTitle: undefined
})
})
const id = +this.route.snapshot.params['id']
}
ngAfterViewInit(): void {
this.formGroup.setControl('general', this.general.formGroup)
}
Having to fully define the 'general' control here feels wrong since I'm going to just replace it with the actual form group from the child. Is there a better way to be doing this? Because it's now properly typed, it seems like I need to do that.
[ ] 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:
Currently mergeValidators
/setValidators
doesn't accept observables... we have the validateOn
that deals with custom errors, but not with validators.
I'd expect to see mergeValidators
/setValidators
accepting observables also, as setValue
/patchValue
.
I have an use case where I set the validators based on another formControl
value, e.g.:
this.formGroup.controls.someControl.setValidators(
this.formGroup.select(({ dependent }) => dependent).pipe(
map(dependent => dependent === 'X' ? [Validators.required, Validators.minlength(3)], customValidator),
),
);
Also, I think we could add support to accept observable in mergeErrors
/setErrors
, that would remove the necessity of having validateOn
... but that's just an idea.
Angular version: 10.x.y
Hi,
in various places I'm getting following error:
Type 'FormGroup<any, any>' is not assignable to type 'AbstractControl'.
It happens for example when I'm using nested FormGroups. The example from the docs also produces this error.
import { FormGroup } from '@ngneat/reactive-forms';
interface Profile {
firstName: string;
lastName: string;
address: {
street: string;
city: string;
};
}
const profileForm = new FormGroup<Profile>({
firstName: new FormControl(''),
lastName: new FormControl(''),
address: new FormGroup({
street: new FormControl(''),
city: new FormControl('')
})
});
Type 'FormGroup<{ street: string; city: string; }, ValidationErrors>' is not assignable to type 'AbstractControl<{ street: string; city: string; }>'.
Types of property 'get' are incompatible.
Type '{ <K1 extends "street" | "city">(path?: [K1] | undefined): AbstractControl<{ street: string; city: string; }[K1]>; <K1 extends "street" | "city", K2 extends keyof { street: string; city: string; }[K1]>(path?: [...] | undefined): AbstractControl<...>; <K1 extends "street" | "city", K2 extends keyof { ...; }[K1], K3 e...' is not assignable to type '(path: string | (string | number)[]) => AbstractControl | null'.
Types of parameters 'path' and 'path' are incompatible.
Type 'string | (string | number)[]' is not assignable to type '[any] | undefined'.
Type 'string' is not assignable to type '[any] | undefined'
[ ] 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
[X] Support request
[ ] Other... Please describe:
I would like to activate the strictTemplate
property in tsconfig but it is complaining that the FormGroup<..,..>
of ngNeat does not match the FormGroup
of angular:
Error: libs/**/**/form.component.ts:37:20 - error TS2322: Type 'FormGroup<MyForm, any>' is not assignable to type 'FormGroup'.
Types of property 'addControl' are incompatible.
Type '<K extends keyof MyForm>(name: K, control: AbstractControlsOf<MyForm>[K]) => void' is not assignable to type '(name: string, control: AbstractControl, options?: { emitEvent?: boolean | undefined; } | undefined) => void'.
Types of parameters 'control' and 'control' are incompatible.
Type 'AbstractControl' is not assignable to type 'FormControl<string, any> | AbstractControl<string[] | null | undefined, any> | undefined'.
Type 'AbstractControl' is missing the following properties from type 'AbstractControl<string[] | null | undefined, any>': touch$, dirty$, disabled$, enabled$, status$
37 <form [formGroup]="form">
I could try to cast it into a FormGroup
of angular but I am also using the eslint rule to not import it from @angular/reactive-form
:s
I know the error is valid but what do you propose ?
[ ] 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 instantiating a FormGroup with asyncValidators an error occurs.
ERROR TypeError: Cannot read property 'next' of undefined at FormControl.setErrors (ngneat-reactive-forms.js:368) at SafeSubscriber._next (forms.js:3241) at SafeSubscriber.__tryOrUnsub (Subscriber.js:183) at SafeSubscriber.next (Subscriber.js:122) at Subscriber._next (Subscriber.js:72) at Subscriber.next (Subscriber.js:49) at Observable._subscribe (subscribeToArray.js:3) at Observable._trySubscribe (Observable.js:42) at Observable.subscribe (Observable.js:28) at FormControl._runAsyncValidator (forms.js:3236)
Should work. Does so when using default angular FormBuilder.
Created a form group with some sync and some async validators (which are fetching stuff from the API)
Angular version: 11.2.0
Browser:
- [x] Chrome (desktop) version 91.0.4472.77
- [ ] 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.16.1
- 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:
Hello,
I'm using the lib and it would be great if there was more methods to remove controls from FormArray
Currently there's only a removeAt(index: number)
method (inherited from @angular/forms) which is not very convenient to remove a control by value or by a given predicate.
I am thinking about something like this in the FormArray class:
removeWhen(predicate: (value: T) => boolean) {
for (let i = 0; i < this.length; ++i) {
if (predicate(this.at(i).value)) {
this.removeAt(i);
}
}
};
remove(value: T) {
this.removeWhen((v) => v === value);
};
I can make a PR if you are interested by such a feature ๐
Thanks for your work ๐
BTW, the link to the repo is outdated on NPM, you should update repo field
It'll be great to add a built-in method to persist the form value to the storage. For example:
const profileForm = new FormGroup<Profile>({
firstName: new FormControl(''),
lastName: new FormControl(''),
skills: new FormArray([]),
address: new FormGroup({
street: new FormControl(''),
city: new FormControl('')
})
});
profileForm.persist(key, storage);
Where the key
is the storage key, and the storage is local
or session
.
I'm submitting a...
[ ] 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'm trying to use FormBuilder a revive interface assignable error.
FormBuilder should work the same as new FormGroup() and new FormArray() instances.
https://stackblitz.com/edit/angular-ivy-fn2teb
Compatibility to use FormBuilder.
Angular version: ^10.2.4
"@ngneat/reactive-forms": "^1.5.1"
Browser:
- [x] 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: v15.6.0
- Platform: Mac
Hi, I really like the idea behind this project and especially the touch$ (but would call it touched$ ;-) it's dirty, it's enabled, it's disabled, it's pristine and ** it's touched**, etc so touch is a bit out of place ) feature.
So what I would propose is to add an abstract class like ControlValueAccessor for use with a Control simply wrapping around a FormGroup (AbstractFormControl actually).
Let's say I have the usual Person object. I want to create a ControlValueAccessor that would wrap around the FormGroup. So finally I could use this component as a form component.
It's much easier now with your reactive-forms but would be even better with an abstract FormControllWrapperValueAccessor.
If I'm not clear enough I can elaborate or maybe create a simple proof of concept.
Idea coming from https://timdeschryver.dev/blog/working-with-angular-forms-in-an-enterprise-environment
[ ] 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:
[ ] 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:
Currently touch$ emits distincted value.
touch$ should emit value on every touch/untouch control events
New added controls linked to lead control touch$ not receive touch events after first lead control touch event.
[ ] 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 invoking mergeValidators
an error is thrown.
The validators are correctly merged without errors.
Given a form group created with the typed FormBuilder
:
const builder = new FormBuilder();
const group = builder.group<{ title: string }>({
title: [ '', Validators.required ],
});
when validators are merged
group.mergeValidators(
(control: NgAbstractControl | AbstractControl<never, never>) => {}
);
then this error is thrown
core.js:6157 ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'validate' of null
TypeError: Cannot read property 'validate' of null
at isValidatorFn (forms.js:754)
at forms.js:766
at Array.map (<anonymous>)
at normalizeValidators (forms.js:765)
at composeValidators (forms.js:776)
at coerceToValidator (forms.js:2756)
at FormGroup.setValidators (forms.js:2951)
at FormGroup.setValidators (ngneat-reactive-forms.js:510)
at mergeControlValidators (ngneat-reactive-forms.js:96)
at FormGroup.mergeValidators (ngneat-reactive-forms.js:481)
at resolvePromise (zone-evergreen.js:798)
at resolvePromise (zone-evergreen.js:750)
at zone-evergreen.js:860
at ZoneDelegate.invokeTask (zone-evergreen.js:399)
at Object.onInvokeTask (core.js:28522)
at ZoneDelegate.invokeTask (zone-evergreen.js:398)
at Zone.runTask (zone-evergreen.js:167)
at drainMicroTaskQueue (zone-evergreen.js:569)
It seems related to the fact that the group
has a null validator. The code that applies a merge doesn't skip it and the following one will use an array like [null, ...]
. Therefore, a deeper investigation is needed ๐
Angular version: 11.2.3
Browser:
- [X] Brave Version 1.23.71 Chromium: 90.0.4430.72 (Official Build) (x86_64)
- [ ] 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: 14.15.1
- Platform: Mac
Others:
Currently, when we subscribe to valueChanges
, we get the complete form object. It'll be useful to create an operator that'll emit only the changed parts.
form.value$.pipe(diff())
[X] Bug report
When I build my project I'm getting compiler errors from the controls in this package. For example, this is the first one that appears:
Error: node_modules/@ngneat/reactive-forms/lib/formControl.d.ts:20:9 - error TS2416: Property 'asyncValidator' in type 'FormControl<T, E>' is not assignable to the same property in base type 'FormControl'.
Type 'AsyncValidatorFn<T, any> | null' is not assignable to type 'AsyncValidatorFn | null'.
Type 'AsyncValidatorFn<T, any>' is not assignable to type 'AsyncValidatorFn'.
Types of parameters 'control' and 'control' are incompatible.
Type 'AbstractControl' is missing the following properties from type 'AbstractControl<T, any>': touch$, dirty$, disabled$, enabled$, status$20 get asyncValidator(): AsyncValidatorFn | null;
Angular version: 11.0.0
For Tooling issues:
- Node version: v15.3.0
- Platform: mac BigSur 11.1
Others:
I saw the pinned issue, but while similar I think this is different as I'm just simply doing a build with your package included.
[ ] 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:
Example from Readme.md which using interface with FormGroup types does not work. (It also doesn't work in real world projects)
It should work without typings problems
https://stackblitz.com/edit/angular-ivy-ek8nym look at address property
I have a typed FormGroup
that contains a few FormControls
, some of them bind to primitive types like number
or string
, and others to objects of my app.
Those FormControls
binded to objects are not showing properties like enabledWhile
or disabledWhile
when I try to call them by mean of this.formGroup.getControl('myObject').enabledWhile(...)
.
Is this on purpose or not? If so, why?
[ ] 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:
TypeScript will not compile the project because of the following errors:
Property 'group' in type 'FormBuilder' is not assignable to the same property in base type 'FormBuilder'.
Property 'controls' in type 'FormGroup<T, E>' is not assignable to the same property in base type 'FormGroup'.
I would expect the project to compile successfully.
Please, let me know if a repo with an example project would be helpful. I'm happy to create one if necessary.
I would like to use this library with Angular v10.
Angular version: 10.0.1
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: v12.18.2
- Platform: MacOS
Others:
- TypeScript: v3.9.5
[ ] 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:
formGroup.valueChanges emit value when setting a validator directive like required because the library call updateValueAndValidity inside setValidators Fn.
formGroup.valueChanges should not emit when adding a directive like the default angular form behaviour we can add the possibility to pass global options for updateValueAndValidity to avoid breaking changes and for easier adoption for big project.
https://stackblitz.com/edit/angular-ivy-kzr2zk
migrating big entreprise project to use ngneat/reactive-forms with minimal breaking changes .
Angular version: 11
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: XX
- Platform:
Others:
In the current version, we tried to provide the maximum typing functionality we could get to make the migration as seamless as possible.
In the next version, we want to add the following features:
get
or getControl
we need to infer the control type explicitly:const profileForm = new FormGroup<Profile>({
firstName: new FormControl(''),
lastName: new FormControl(''),
skills: new FormArray([]),
address: new FormGroup({
street: new FormControl(''),
city: new FormControl('')
})
});
const cityControl = profileForm.getControl('address', 'city') as FormControl<string>;
We need to use TS to automatically infer the type so that users can write:
const cityControl = profileForm.getControl('address', 'city');
value
and errors
type:type Errors = {
passwordMismatch: boolean;
}
const form = new FormGroup<ChangePasswordForm, Errors>({
password: new FormControl(),
repeatPassword: new FormControl()
},
{ validator });
// The signature of validator should automatically be:
function validator(control: FormGroup<ChangePasswordForm>): Errors | null {}
new FormControl({ disabled: true, value: '' })
[ ] 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:
Trying to upgrade to Angular 10 and on build I get this error
ERROR in node_modules/@ngneat/reactive-forms/lib/formControl.d.ts:7:14 - error TS2610: 'asyncValidator' is defined as an accessor in class 'FormControl', but is overridden here in 'FormControl<T, E>' as an instance property.
I would expect it to build without the error above
After upgrading to Angular 10, simply try to run the app.
Angular version: 10.1.0
This was asked in a different issue and I was told it was unrelated so I thought to open up a new issue for any incoming PRs. I have not had the opportunity to dive too deply in this but I am wondering if the asyncValidator needs to be in the FormControl class or if it could just use the inherited property.
Thanks again for your quick response on the original question.
[ ] 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:
I'm investigating some memory bloat in a large form, and noticed that a lot of the form controls are being retained when navigating to/back to the page that contains it, as evidenced by the memory profiler in chrome:
While looking through the code:
reactive-forms/projects/ngneat/reactive-forms/src/lib/formControl.ts
Lines 43 to 54 in 2a56454
It appears that none of these subscriptions or their Subjects are ever completed.
In the case of my form it looks like around 50000 observables are leaked every time I navigate to the specific tab that contains the form.
Note that I'm unsubscribing from the ones that I'm using, but I'm seeing leaks of others I don't use at all, such as errors$
Subscriptions should be completed somehow.
Should be reproducible in any app by default as long as the form is being re-created. Such as wrapping it in an *ngIf
. I can't find a working stackblitz or I would've added a repro myself.
Prevents memory leaks.
Angular version: 11.1.0
[ ] 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:
I would like to propose ability to pass some custom observable data to form to be able to pass it through form control. It is really useful if that data is dependent on something in form model and we want to for example create that form in dedicated service.
<kendo-multiselect
#list
[data]="control.data$ | async"
[filterable]="true"
textField="text"
valueField="value"
placeholder="T-shirt size"
[formControl]=[control]
>
</kendo-multiselect>
and in service
createControl(){
const control = new FormControl<number>(undefined);
control.passData(someObservableData$);
}
here it is a bit simplified and the use cases is not very visible but imagine this data being dependent on other form values from for example parent form. And some validations and disabled states also also depend on that data in other field etc.
I'm currently working on such form and such feature would be really useful and allow me to do everything much more neatly.
It become really usefull if data is used for a field in model that is in form array and is dependent on field from parent form group.
Just not sure if it should be observable or just "any" and let user decide what is needed.
[x] Regression
[x] Bug report
With regular Angular forms calling setValidators
does not automatically call updateValueAndValidity
.
We had to manually call updateValueAndValidity
and had the ability to pass options, like {onlySelf: true}
to that method.
My code broke after migrating to this library, since I used to call updateValueAndValidity
with additional options.
The setValidators
method should therefore be extended by an optional parameter options
, which is passed straight into updateValueAndValidity
.
I guess the same behavior applies to clearValidators
.
Angular version: 8
Browser:
- [x] Chrome (desktop) version XX
hasError
- typed?getError
- typed?errorsChanges$
?Maybe expose something such as:
<div *ngIf="control.hasErrorAndTouched('required')"></div>
<div *ngIf="control.hasErrorAndDirty('required')"></div>
Instead of:
<div *ngIf="control.hasError('required') && control.touched"></div>
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[ ] Feature request
[x ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:
Hello, neat library ;) And looking to be a great time saver
I'm puzzled by the possibility of initializing a FormControl
with bad data. Please see the following screenshots:
Here, I forgot to initialize the activityName
form control with a value.
Later, I feed this form control to a function that requires a string:
The compiler doesn't have my back unfortunately, and I get a runtime error!
I would expect to have as much type safety as possible at compile time.
I'm not familiar with writing generics producing code. But a quick prototype shows me it is possible to add this constraint at the language level.
Is this a bug? I can't se a valid use case for the current behavior.
I can see you mark the formState as optional here:
If that's really a necessity, I would expect the underlying form control value to return a string | undefined
(which would still be annoying be better than getting a runtime error)
Thanks :)
[ ] 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 typescript compiler rejects the reactive-forms FormGroup type. This error occurs:
ERROR in libs/frontend/change-maker/feature-more/src/lib/change-password/change-password.component.html:13:9 - error TS2322: Type 'FormGroup<ChangePasswordForm, any>' is not assignable to type 'FormGroup'.
Types of property 'get' are incompatible.
Type '{ <K1 extends "confirmPassword" | "currentPassword" | "newPassword">(path?: [K1] | undefined): AbstractControl<ChangePasswordForm[K1]>; <K1 extends "confirmPassword" | "currentPassword" | "newPassword", K2 extends keyof ChangePasswordForm[K1]>(path?: [K1, K2] | undefined): AbstractControl<ChangePasswordForm[K1][K2]>; <K1 extends "confirmPassword" | "currentPassword" | "newPassword", K2 extends keyof ChangePasswordForm[K1], K3 extends keyof ChangePasswordForm[K1][K2]>(path?: [K1, K2, K3] | undefined): AbstractControl<ChangePasswordForm[K1][K2][K3]>; (path?: string | undefined): AbstractControl<any>; }' is not assignable to type '(path: string | (string | number)[]) => AbstractControl | null'.
Types of parameters 'path' and 'path' are incompatible.
Type 'string | (string | number)[]' is not assignable to type '[any] | undefined'.
Type 'string' is not assignable to type '[any] | undefined'.
13 <form [formGroup]="form" (submit)="submit()">
~~~~~~~~~~~~~~~~~~
libs/frontend/change-maker/feature-more/src/lib/change-password/change-password.component.ts:21:16
21 templateUrl: './change-password.component.html',
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component ChangePasswordComponent.
There are no type errors.
This is the code used. Note that I have strict
mode in my tsconfig.json
import { FormControl, FormGroup } from '@ngneat/reactive-forms';
interface ChangePasswordForm {
currentPassword: string;
newPassword: string;
confirmPassword: string;
}
@Component({
selector: 'cm-more-change-password',
templateUrl: './change-password.component.html',
styleUrls: ['./change-password.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ChangePasswordComponent extends ComponentStore<State> {
readonly form = new FormGroup<ChangePasswordForm>(
{
currentPassword: new FormControl('', Validators.compose([(ac) => Validators.required(ac)])),
newPassword: new FormControl(
'',
Validators.compose([(ac) => Validators.required(ac), Validators.pattern(Config.regex.password)])
),
confirmPassword: new FormControl(
'',
Validators.compose([(ac) => Validators.required(ac), Validators.pattern(Config.regex.password)])
),
},
{ validators: (ac) => ConfirmPasswordValidator.MatchPassword(ac, 'newPassword', 'confirmPassword') }
);
}
HTML snippet:
<form [formGroup]="form" (submit)="submit()">
<im-input label="Current Password">
<ion-icon slot="start" name="lock-closed"></ion-icon>
<input formControlName="currentPassword" type="password" placeholder="Current Password" />
<im-error *ngIf="!form.controls.currentPassword.valid && form.controls.currentPassword.touched">
Please enter your current password.
</im-error>
</im-input>
<im-input label="New Password">
<ion-icon slot="start" name="lock-closed"></ion-icon>
<input formControlName="newPassword" type="password" placeholder="New Password" />
<im-error *ngIf="!form.controls.newPassword.valid && form.controls.newPassword.touched">
Your password must be minimum 8 characters, contain at least 1 letter, 1 number, and 1 special
character.
</im-error>
</im-input>
<im-input label="Confirm New Password">
<ion-icon slot="start" name="lock-closed"></ion-icon>
<input formControlName="confirmPassword" type="password" placeholder="Confirm New Password" />
<im-error *ngIf="!form.controls.confirmPassword.valid && form.controls.confirmPassword.touched">
Your new password must be valid match.
</im-error>
</im-input>
<!-- Implicit button for form when pressing enter button -->
<button style="display: none;" [disabled]="!form.valid"></button>
</form>
Angular version: 9.1.11
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 84.0.522.48
For Tooling issues:
- Node version: XX 12.13
- Platform: Docker, Windows
Others:
[x] Bug report
When testing a simple component that has a setup form method on init the test for an invalid form fails. The form is valid without having values.
Swapping the ngneat form builder for the Agnualr form builder from angular core it works fine.
The test will output the form's invalid property as true.
Logging the output in the browser works as expected.
Jest is used as a test runner
The test should output an invalid form after setup.
// component
@Component({
selector: 'user-login',
changeDetection: ChangeDetectionStrategy.OnPush,
styleUrls: ['./login.component.scss'],
templateUrl: './login.component.html'
})
export class LoginComponent implements OnInit {
form;
...
constructor(
private fb: FormBuilder,
) {}
ngOnInit(): void {
this.form = this.createForm();
// console.log("component", this.form.valid)
// console.log(this.form)
}
private createForm() {
return this.fb.group({
username: ['', Validators.required],
password: ['', [Validators.required, Validators.minLength(10)]]
});
}
}
// test
import { ReactiveFormsModule } from '@angular/forms';
import { FormBuilder, FormGroup } from '@ngneat/reactive-forms';
...
beforeEach(waitForAsync(() => {
...
TestBed.configureTestingModule({
declarations: [LoginComponent],
imports: [
ReactiveFormsModule
],
providers: [
FormBuilder,
{ provide: UserFacade, useValue: userFacade }
]
}).compileComponents();
}));
beforeEach(async () => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
});
...
describe('form invalid', () => {
it('should NOT call userFacade.login', () => {
component.ngOnInit();
console.log(component.form.valid) // ouput is true
});
...
Angular version: 10.1.0
ng neat reactive forms version: 1.3.1
Browser:
- [x] Chrome (desktop) version 85.0.4183.102
- [x] Firefox (desktop) version 80.0.1
For Tooling issues:
- Node version: 12.18.3
- Platform: Macos
My applicaiton package.json shows the following
`"@ngneat/reactive-forms": "1.7.0",`
but the package with the exposing of the diff() function is labelled 1.6.1
As a result, I cannot upgrade to get the use of the diff() function.
There seems to be an issue with the package versions.
Cheers
[ ] 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:
Two new Control Methods patchEnable() & patchDisable(). They base on setEnable(), setDisable() methods where new behavior is possibility to disable list of controls.
Idea behind this methods is base on patchValue() method.
This change would is completely new and behaves different base on form element use:
This would give possibility of maintaining form multiple form controls at a time like in already existing method patchValue().
[x] 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:
interface FiltersForm {
usersSelect: any;
periodFrom: string;
periodTo: string;
dueDateFrom: string;
dueDateTo: string;
}
public readonly form: FormGroup<FiltersForm> = this.formBuilder.group<FiltersForm>({
usersSelect: null,
periodFrom: '',
periodTo: '',
dueDateFrom: '',
dueDateTo: ''
});
this.form.patchValue({ usersSelect: null });
last line breaks build;
ERROR in filters.component.ts:120:7 - err
or TS2769: No overload matches this call.
Overload 1 of 2, '(valueOrObservable: Observable<DeepPartial<ControlsValue<FiltersForm>>>, options?: Pick<ControlOptions, "onlySelf" | "em
itEvent"> | undefined): Subscription', gave the following error.
Argument of type '{ usersSelect: null; }' is not assignable to parameter of type 'Observable<DeepPartial<ControlsValue<FiltersForm>>>'.
Object literal may only specify known properties, and 'usersSelect' does not exist in type 'Observable<DeepPartial<ControlsValue<Filte
rsForm>>>'.
Overload 2 of 2, '(valueOrObservable: DeepPartial<ControlsValue<FiltersForm>>, options?: Pick<ControlOptions, "onlySelf" | "emitEvent"> |
undefined): void', gave the following error.
Type 'null' is not assignable to type 'DeepPartial<any> | undefined'.
120 this.form.patchValue({ usersSelect: null });
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
filters.component.ts:28:3
28 usersSelect: any;
~~~~~~~~~~~
The expected type comes from property 'usersSelect' which is declared here on type 'DeepPartial<ControlsValue<FiltersForm>>'
When change type of usersSelect to usersSelect: number | null; error disappears.
Deep partials to work with any;
DeepPartial = any;
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:
Control is valid when Validators.required is set.
[X] Bug report
Radio control is always valid
To work same as native FormControl
https://stackblitz.com/edit/angular-ivy-emnm3t?file=src%2Fapp%2Fapp.component.ts
Switch FormControl between @angular/forms and @ngneat/reactive-forms and look at valid/invalid status.
Validate the radio control
Angular version: ^11.0.8
Browser:
- [x] Chrome (desktop) version XX
For Tooling issues:
- Node version: v14.16.0
- Platform: Windows
[ ] 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:
controls created using formBuilder do not appear to have all the features that they should
this.formGroup = this.formBuilder.group({
categoryKey: null,
description: null
});
// does not work
this.formGroup.controls.categoryKey.errors$.subscribe()
// works
const control = new FormControl('');
control.errors$.subscribe(errors => {});
In this sample shown, using a directly created form control by copy pasting from the docs, the errors$
observable is present. However, trying to access the errors$
on my control created using formBuilder gives me a TS linting error saying it doesn't exist and suggesting the vanilla errors object
As far as I can tell from the docs, it sounds like controls made with formBuilder should also be fully featured. I checked other items like disabled$
etc and none of them appear on the item made with formBuilder
just create something with formBuilder and try to access items like errors$
To fix what appears to be broken behaviour (I apologize if I am just doing something wrong here or misinterpreting how it should work, in which case possibly a clarification added to the docs could help instead?)
Angular version: 7.2.15
TS version: 3.2.4
Browser:
- [x] Chrome (desktop) version 84
- [ ] 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:
I have a few fields on a FormGroup
, and some of them I set an enabledWhile
function to enable/disable them based on whether other fields have certain values or not. So far so good. The problem arises when I try to use the FormGroup
to edit an existing item and execute a patchValue
with all the data needed to update the FormGroup
, and then the issues start: the fields that don't have any conditional enabled/disabled state, work just fine, but those that have the enableWith
function applied don't get their value update on the UI (despite the FormGroup.value
reflecting the values correctly).
I have to execute a setTimeout(this.formData.patchValue(data))
right below the first patchValue
to update these neglected fields and reflect the value on the UI.
I would expect that when I perform a patchValue
, that the FormGroup
gets correctly updated, even for those fields that have a enabledWhile
/disabledWhile
method applied.
Angular version: 11.0.0
Browser:
- [X] Chrome (desktop) version 87.0.4280.66
- [ ] 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:
In the types exported by this library, disabled$
, enabled$
and status$
are typed as any
.
FormArray, FormGroup and FormControl all have this problem.
Check out:
https://cdn.jsdelivr.net/npm/@ngneat/[email protected]/lib/formGroup.d.ts
readonly disabled$: any;
readonly enabled$: any;
readonly status$: any;
They should have the proper type.
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.