GithubHelp home page GithubHelp logo

cloudnc / ngx-sub-form Goto Github PK

View Code? Open in Web Editor NEW
314.0 9.0 33.0 14.7 MB

Utility library for breaking down an Angular form into multiple components

Home Page: https://cloudnc.github.io/ngx-sub-form

License: MIT License

JavaScript 2.29% TypeScript 80.98% HTML 14.95% SCSS 1.77%
angular angular-forms angular-reactive-forms

ngx-sub-form's People

Contributors

acadianaapps avatar ambeur avatar anschm avatar erikmom avatar joschuaschneider avatar lppedd avatar maxime1992 avatar ntziolis avatar waterstraal avatar zakhenry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ngx-sub-form's Issues

should `createFormArrayControl` accept null values for the `value` object

When dealing with FormArray, I believe a common use case is to click a button to add an empty entry in the array and later on from the UI fill it up.

Currently the definition is:

protected createFormArrayControl(
  key: ArrayPropertyKey<StackedNonCuttingCylinders.AsObject> | undefined,
  value: ArrayPropertyValue<StackedNonCuttingCylinders.AsObject>,
): FormControl

and value doesn't accept an object with all the required keys but with null values.

I think it should.

Anyone second that?

Allow nested forms for rootFormComponents and subformsComponents

https://stackblitz.com/edit/ngx-sub-form-basics-algasm?file=src%2Fapp%2Fspaceship-container%2Fspaceship-form%2Fspaceship-form.component.ts

In the above I have put some comments, remarks when global searching "@author" (case insensitive)

when we use:

  protected getFormControls(): Controls<Spaceship> {
    return {
      name: new FormControl(),
      builtInYear: new FormControl(),
      group1: new FormGroup({
        config: new FormControl(),
        hehe:   new FormControl('hehe'),
      })
    }
  }

things start to fall apart, as the Stackblitz shows.

Also how do we type out such complex structures? We would need new generic abstractions for formGroup and formArray GITHUB.

As I have tried it with FormArray it failed completally, but i guess @maxime1992 is already working on something with FormArray.

Who's using ngx-sub-form?

Hi everyone 👋!

Out of curiosity, we'd love to heard from people using ngx-sub-form whether you're using it for small side projects or larger projects at work 👍.

If you feel like sharing with us know, feel free to use the following template (or not):

- I/we use `ngx-sub-form` [for personal projects]/[at work (COMPANY_NAME), with at least X people using the library]
- I/we are using `ngx-sub-form` on prod for X projects that are used by more than X customers every [days/months/years]
- Searching for `from 'ngx-sub-form'` in the whole code base gives me X hits
- So far my/our experience with `ngx-sub-form` has been [awful/good/great/awesome]
- If I could vote for an epic feature it would be:
- Anything else you want to share with us:

(feel free to tweak the above as you please and answer only what can/want)

Thanks for taking the time to share 🙏!

FormGroup with transformation isn't handled correctly

When using NgxSubFormRemapComponent and thus overriding

transformToFormGroup
transformFromFormGroup

I've noticed formGroup.value isn't transformed correctly during the registerOnChange phase.
Here

// this is required to correctly initialize the form value
this.onChange(this.formGroup.value);

it should be

// this is required to correctly initialize the form value
this.onChange(this.transformFromFormGroup(this.formGroup.value));

If we don't do this, the transformed value is emitted only on the first change.

Lazy loading causes ExpressionChangedAfterItHasBeenCheckedError (NG-ZORRO?)

Even with this workaround, it seems that lazy loading a component doesn't work. At least that happens when using the NG-ZORRO Tab's lazy loading mechanism.

this.subscription = this.formGroup.valueChanges
  .pipe(
    // this is required otherwise an `ExpressionChangedAfterItHasBeenCheckedError` will happen
    // this is due to the fact that parent component will define a given state for the form that might
    // be changed once the children are being initialized
    delay(0),

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ng-pristine: true'. Current value: 'ng-pristine: false'.

Usage example:

<div [formGroup]="formGroup">
  <input [formControlName]="formControlNames.name">

  <div [formArrayName]="formControlNames.families">
    <nz-tabset nzTabPosition="top" nzSize="small" nzType="card">
      <nz-tab *ngFor="let c of families.controls; index as i" [nzTitle]="c.value.name">
        <ng-template nz-tab>  <!--  This -->
          <app-family [formControlName]="i"></app-family>
        </ng-template>
      </nz-tab>
    </nz-tabset>
  </div>
</div>

I'm trying to understand, but with no luck 'til now.

`[ngValue]` doesn't work but `[value]` does

Followup from #105 as that was more of a question but found a bug. (there's a stackblitz there that can be used to see the bug)

It appears that it's not possible to use [ngValue] but [value] works.
Docs: https://angular.io/api/forms/SelectControlValueAccessor

Not very clear but apparently [ngValue] would be for objects while [value] should be for strings.
Unsure why value is currently working.

Not 100% sure it's worth spending any time on this would still be good to have a clarification.

If anyone has any idea BTW, please let me know!

Can't compile in the newest angular preview (~9.0.0-next.7)

    ERROR in node_modules/ngx-sub-form/lib/ngx-root-form.component.d.ts(18,40): error TS2707: Generic type 'NgxRootFormComponent<ControlInterface, FormInterface>' requires between 1 and 2 type arguments.

I'm using very strict typescript settings:

		"noImplicitAny": true,
		"noImplicitReturns": true,
		"noImplicitThis": true,
		"noUnusedParameters": true,
		"strictNullChecks": true,
		"strictFunctionTypes": true,
		"strictPropertyInitialization": true,

image

Hook to be warned when the form has changed?

I think that a very common thing with form is subscribing to the form value and also start that observable with the current form value.

Example of doing that with this lib:

this.formGroup.valueChanges
      .pipe(
        startWith(this.formGroupValues),
        tap(() => this.doSomething())
      );

Annoying part is that in doing so, we have to manage the subscription and the cleanup when the component's being destroyed.

I wonder if it would be worth having a method taking care of the whole observable/async part so that to react to a form change we would only need to do something like that:

@MyComponent({...})
class MyComponent extends NgxSubForm<FormInterface> {
  protected getFormControls(): Controls<FormInterface> {
    return {...};
  }

  protected onFormUpdate({ formValue, isInitialValue }: FormChange<FormInterface>) {
    // do something with formValue, also possible to make a condition if you don't want
    // to react to the initial value
  }
}

@zakhenry what do you think?

`DataInput` decorator has a type error when used with an array

In the following example:

export class RotorsFormComponent
  extends NgxAutomaticRootFormComponent<Letter[], RotorsForm>
  implements NgxFormWithArrayControls<RotorsForm> {
  @DataInput()
  @Input('rotors')
  dataInput: Letter[] | null | undefined;

We've got an error:

ERROR in apps/enigma/src/app/rotors/rotors-form/rotors-form.component.ts(26,4): error TS2345: Argument of type 'RotorsFormComponent' is not assignable to parameter of type 'NgxRootFormComponent<any, any>'.
      Types of property 'dataInput$' are incompatible.
        Type 'BehaviorSubject<Letter[] | null | undefined>' is not assignable to type 'BehaviorSubject<Required<any> | null | undefined>'.
          Type 'Required<any> | null | undefined' is not assignable to type 'Letter[] | null | undefined'.
            Type 'Required<any>' is missing the following properties from type 'Letter[]': length, pop, push, concat, and 26 more.

This occurs as soon as we use an array on a top level form which is using the DataInput decorator.

lodash dependency

$ npm install ngx-sub-form
.....
$ ng serve
....
ERROR in ./node_modules/ngx-sub-form/fesm5/ngx-sub-form.js
Module not found: Error: Can't resolve 'lodash-es' in '/home/matt/WebstormProjects/food4fitness/node_modules/ngx-sub-form/fesm5'
ERROR in ./node_modules/ngx-sub-form/fesm5/ngx-sub-form.js
Module not found: Error: Can't resolve 'lodash-es/isEqual' in '/home/matt/WebstormProjects/food4fitness/node_modules/ngx-sub-form/fesm5'
$ npm install lodash-es
...
all is well

A form value can be an old one

This is a tricky issue to repro and will probably only repro through a test to get the timing right.

But I just hit a case that drove me insane where my form was considered valid, while the value that was passed clearly wasn't.

@zakhenry and I identified the potential issue and it might be coming from the fact that we do:

 this.subscription = this.formGroup.valueChanges
      .pipe(
        // ...
        delay(0),
        map(changes => {
          this.onChange(changes)
        }),
        // ...
      )

But apparently that value coming from the form might not be mutated like I thought it'd and thus, the validity check would succeed on the RootFormComponent because the form might now be valid while sending the previous value.

FormArray usecase

First of all, nice work! Really.

I was having a look at your Droids/Vehicles example, and a question emerged.
What do I do if I need to handle a FormArray?
An example to clarify: what if I want the user to be able to pick multiple colors for a Spaceship? I'll have to deal with multiple (1...N) color picker. This is one thing missing from the README.

image

Notify the compatible versions in the readme

Hi

It was just to suggest you to explicitly write the compatible version of Angular somewhere where it's easy to see it like the README ?
NB: Howerver today, we can see it in the Changelog file and the release tab in github :)

I'm thinking about something like:

Angular <=7: V2.7.1
Angular >=8: Latest

Thanks and nice job for the lib guys !

Custom change detection with onPush is broken

Related to Angular issues with ControlValueAccessor and OnPush components:

Currently, setting a component to use the OnPush change detection strategy is not safe with ngx-sub-form as you'd end up with a "shift". If you type "Hello" in an input and then add "A" the displayed value would be "Hello". If after that you add a B, the value displayed would be "HelloA", etc. Late by 1 change basically.

When calling the onChange hook from the ControlValueAccessor, Angular should run a change detection but it seems that it's not the case.

Workaround

Not a beautiful one but at least simple and it's still possible to use OnPush...

In order to trigger a change detection, we can use the async pipe with a value coming from the form. So for every form that has at least a child (otherwise it's not needed), you can do the following: [attr.data-ngx-sub-form-issue-93]="formGroup.valueChanges | async".

For e.g., from a sub component:

<div [formGroup]="formGroup" [attr.data-ngx-sub-form-issue-93]="formGroup.valueChanges | async">
  <-- ... -->
</div>

OnDestroy shouldn't set the FormControl value to null

The ngOnDestroy method

public ngOnDestroy(): void {
  this.fg = null;

  if (this.subscription) {
    this.subscription.unsubscribe();
  }

  if (this.onChange) {
    this.onChange(null);
  }
}

currently sets the original FormControl value to null.
I'd say it's not really the responsibility of the library to set that value to null, thus

if (this.onChange) {
  this.onChange(null);
}

should be removed.

Emit initial value should emit only if transformed value is different than the initial one

When the form is created, if emitInitialValueOnInit is true (defaults to true...) then we call the onChange callback:

if (index > 0 || (index === 0 && this.emitInitialValueOnInit)) {
if (this.onChange) {
this.onChange(this.transformFromFormGroup(changes));

This has for effect to set the current value as dirty, here's an example on our demo app (at startup, on a given robot):

image

In most cases, this is just a bug and we should have the value set as pristine.

BUT, there's one case where it shouldn't be pristine: If the sub component extends NgxSubFormRemapComponent and one of the properties is somehow computed. It doesn't mean that this is impure but let say you pass an object with 3 values:

  • a: number
  • b: number
  • c: number (sum of A and B)

When you pass the initial values a: 1, b: 2, c: null you'd expect to get back straight away a: 1, b: 2, c: 3.

In which case, the control should be set as dirty because we may want to save the new value.

QUESTION:

Do we really want to handle that case?
If yes, then we should fix the wrong behavior by making a deep comparison.

If not, then we shouldn't broadcast the first value at all.

How to have validatorFN for FormControl inside getFormControls() ?

I know there is getFormGroupControlOptions but this is validation for the entire formGroup right? (as indicated by (formGroup) => {} ) - FormGroup - level.

How can I use validation on a FormControl level?

Here in my stackblitz im using the same validatorFN validatorWithDeps in a normal angular way and inside getFormControls() the ngx-sub-form way. How can I yield the same results? For ngx-sub-form its undefined. (because of scoping ...)

STACKBLITZ

Steps to reproduce:

  • open browser-console
  • type stuff into top field ("Enter you email")
  • type stuff into field with "12345" in it.
  • For top field the validator can resolve the values. For ngx-sub-form it cant.

One sub form randomly tells me that formControlName must be used within formGroup

I've been rewriting an old form that grown mad in one of our app, it worked weel for 3 sub-forms but there is one I can't get working.

Angular tells me formControlName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it an existing FormGroup instance (you can create one in your class), which I'm pretty sure the library's supposed to do automatically.

I've looked so many times for the difference between this subform and the others and I can't spot a difference.

By the way I'm on Angular: 8.2.7 if it makes any difference

ExemptionForm

<form [formGroup]="formGroup">
  <app-exemption-context-form [formControlName]="formControlNames.context"></app-exemption-context-form>
  <app-exemption-type-form [formControlName]="formControlNames.type"></app-exemption-type-form>
  <app-exemption-justification-form [formControlName]="formControlNames.justification"></app-exemption-justification-form>
</form>
export class ExemptionFormComponent extends NgxAutomaticRootFormComponent<ExemptionFormData> implements OnInit {
  @DataInput()
  @Input()
  dataInput: ExemptionFormData;

  @Output()
  dataOutput: EventEmitter<ExemptionFormData> = new EventEmitter();

  protected getFormControls(): Controls<ExemptionFormData> {
    return {
      context: new FormControl(),
      type: new FormControl(),
      justification: new FormControl(),
    };
  }

  ngOnInit() {
    // By the way this is another issue that I'll have to fill,
    // I couldn't set form's value without this
    this.dataInput$.subscribe(d => this.formGroup.setValue(d));
    this.formGroup.updateValueAndValidity();
  }
}

ExemptionTypeForm

<fieldset>
  <legend>Type de dérogation</legend>

  <mat-form-field appearance="outline">
    <mat-select [formControlName]="formControlNames.type" placeholder="Type de dérogation" required>
      <mat-option *ngFor="let type of exemptionTypes" [value]="type">
        {{ type.name }} - {{ type.description }}
      </mat-option>
    </mat-select>
    <mat-hint>...</mat-hint>
  </mat-form-field>
  
  <mat-form-field appearance="outline">
    <mat-select placeholder="Équipe"
        [compareWith]="idComparison" 
        [formControlName]="formControlNames.chargedTeam">
      <mat-option *ngFor="let team of teams" [value]="team">
        {{ team.name }}
      </mat-option>
    </mat-select>
    <mat-hint *ngIf="teams.length > 1">...</mat-hint>
  </mat-form-field>
</fieldset>
@Component({
  selector: 'app-exemption-type-form',
  template: `...`,
  styles: [],
  providers: subformComponentProviders(ExemptionTypeFormComponent)
})
export class ExemptionTypeFormComponent extends NgxSubFormComponent<ExemptionFormType> {
  public exemptionTypes: ExemptionType[] = [];
  public teams: Team[] = [];

  protected getFormControls(): Controls<ExemptionFormType> {
    return {
      chargedTeam: new FormControl(null, { validators: [Validators.required] }),
      type: new FormControl(null, { validators: [Validators.required] })
    };
  }

  idComparison(o1: WithID, o2: WithID): boolean {
    return o1.id === o2.id;
  }
}

Thanks in advance for the help, and your work on the library 🙂

How to flat data coming from sub-components.

STACKBLITZ

lets say I have to reuse a sub component OVER and OVER in my app. In this case a field with phoneNr and phoneNrConfirm

  protected getFormControls(): Controls<Phone> {
    return {
      phone: new FormControl(null, { validators: [Validators.required] }),
      phoneConfirm: new FormControl(null, { validators: [Validators.required] }),
    };
  }

it has INTERNAL validation (like password confirm)

  public getFormGroupControlOptions(): FormGroupOptions<Phone> {
    return {
      validators: [
        formGroup => {
          if (formGroup.value.phone !== formGroup.value.phoneConfirm) {
            return {
              phoneMustMatch: true,
            };
          }

          return null;
        },
      ],
    };
  }

BUT there will also be EXTERNAL VALIDATION like

  <p>london Number +44 123456</p>
  <app-phone-form [formControlName]="formControlNames.phone" pattern="\+44[0-9]+"></app-phone-form>

  <p>italian Number +39 123456</p>
  <app-phone-form [formControlName]="formControlNames.phone2" pattern="\+39[0-9]+"></app-phone-form>

(of course a Validator.pattern(...)) could be used in app-personal-details-form. This would lead to the same problems.

  • A pattern validator expects a string and not an object like `phone: '123', phoneConfirm: '123'.
  • For my validation and for my form / api call what ever only phone: '123 is important. I only need phoneConfirm for UX and Validation.
  • The orig FormData should become:
{
  gender: 'Male',
  phone: '123',
};

instead of

{
  gender: 'Male',
  phone: {
    phone: '123',
    phoneConfirm: '123'
    }
};

(there is no valuable information in a Confirmation Field)

It would be nice to have a cherryPick() method that will handle this issue. It will flat out the data object from subform into a primitive. Therefore the subforms value can be validated with angulars default tools on a higher level.

  • Is this already possible with ReMap?
  • How would one type out this flattening/ reducing.

In my real use case I have a {password + passwordConfirm + passwordStrengthIndicator} subcomponent and different password requirements that I would like to handle on a higher level.

As a workaround I can of course add a input to my app-phone-form that will handle the EXTERNAL VALIDATION ... but maybe I can solve this differently.

onFormUpdate event doesn't fire for radio button

https://stackblitz.com/edit/ngx-sub-form-form-update-field-test

I have a radio button hooked up to show/hide 2 different subforms. What I'd like to do is save the data of each subform so that it's not lost when the subform gets destroyed by switching to a different subform. To do this I need an event from the radio button, but it isn't appearing in onFormUpdate(). I have to use the valueChanges Observable on the control itself.

Thanks for the awesome library :-)

How can we make a checkbox-group subform ?

I have to make some kind of "checkbox-group" for a project coded with IONIC 4 for a mobile app. And i will love use that very nice lib !

This widget will need to work exactly like a "select" with the "multivalues" option enabled. The idea behind the question is that we prefer the look and feel of a "checkbox list" than a "select" dropdown on a phone.

In fact i would love to have a component like "radiogroup" or "select" that directly display a checkbox group.

To do that, is it better to create this widget as a sub-form of my main form for each "checkbox-group" or to create a specific "widget" just for that ?

What is the best method to do that with ngx-sub-form ?

How to reset formGroupValues and their subform to null

Hi,

Is it possible to reset formGroupValues and their corresponding subform to null?

I tried this:
this.formGroup.patchValue({ Quarter: null, CustomFrom: null, CustomTo: null, });

So the formGroupValues will change, but the formControl of the values don't.
After a quick look to this ngx-sub-form.component.ts the problem seems to be in line 202.

Is there a special way to patch some form-fields to NULL (I mean NULL, not an falsy value like it is described in the ngx-sub-form.component.ts)?

`oneOf` validator for polymorphic data

When dealing with polymorphic data and using the remap functions it'd be nice to have a oneOf validator. It'd take as argument keys of the formGroup so it'd also be type safe.

Example here https://github.com/cloudnc/ngx-sub-form/blob/6ecdb2017e/src/app/main/listing/listing-form/vehicle-listing/vehicle-product.component.ts#L24-L25

And it could look like the following:

public getFormGroupControlOptions(): FormGroupOptions<YourPolymorphicForm> {
  return {
    validators: [NgxSubFormValidators.OneOf('prop1', 'prop2', 'prop3')],
  };
}

Parent form incorrectly reports error for sub component after disable/enable

I'm submitting a ...

[ ] Regression (behavior that used to work and stopped working in a new release)
[ X] Bug report 
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see 

Current behavior

Creating a form structure as below, with sub form "cat" having a subform for "appendages" similar to the OneListing[] approach taken in github demo.

{
  "id": 100408,
  "name": "My cat with one long arm with 6 fingers",
  "type": "CAT",
  "cat": {
    "appendages": [
      {
        "fingers/digits":  6, //required
        "length": 40127
      }
    ],
    "name": "HOMER"
  },

I.e. the following components exist

export interface AnimalForm {
  id: number;
  name: string;
  type: 'cat' | 'dog',
  cat: CatForm
}
export class AnimalRootFormComponent extends NgxRootFormComponent<Animal, AnimalForm> {

export class CatSubFormComponent extends NgxSubFormRemapComponent<CatForm, CatForm> {

export class AppendagesFormComponent extends NgxSubFormRemapComponent<Appendage[], AppendagesForm> implements OnChanges {

export class AppendageFormComponent extends NgxSubFormRemapComponent<Appendage, Appendage> implements OnInit, OnDestroy {

  • Disable and enable the form,
  • Change appendage fingers value to 5
  • Calling formGroup.valid returns false eventhough form is valid.

The following sub forms are valid

appendages: Valid
appendage: Valid
cat: Invalid
cat.formGroup.controls.appendage.valid: Invalid
cat.formGroup.controls.appendage.errors = {
    appendages: []
}

Expected behavior

Disabling and enabling the form should result in a valid form.

Angular version: ~8.0.0

Still an issue

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: 10.9.0 
- Platform: windows

Expose form validity

I have a button to save the form outside the form component, I want to enable it only when the form is valid. This is easy if you have a reference to the formgroup: [disabled]="!form.valid"

If you'd expose this property of the form with a getter I can get this functionality back.

public get valid(): boolean {
	return this.formGroup.valid;
}

formGroup.pristine is initially false when a sub-form is added

If there is only one NgxRootFormComponent the formGroup is initially pristine, but after adding a NgxSubFormComponent the formGroup.pristine returns false. Check my stackblitz for an example. After deleting the app-spaceship-config-form sub-form formGroup.pristine returns true, as expected. When the sub-form is present and after pre filling the form, formGroup.pristine changes from false to true.

Tl;dr formGroup.pristine should be true even if there is a sub-form.

No output emitted when value changed to initial value set from Subject.next()

So, I'm not sure if this is an issue with ngx-sub-form or my understanding of how to accomplish this. I want to be able to set the initial value of a select or radio button of an ngx-sub-form's NgxAutomaticRootFormControl or NgxRootFormControl. I tried using the technique described on the blog https://dev.to/maxime1992/building-scalable-robust-and-type-safe-forms-with-angular-3nf9 where it mentions under spaceship-container.component.ts to use an rxjs Subject and call it's .next() method. This does work, but then if I change a value of the select/radio and then try to go back to the initial choice, with the auto method I get no output and with the manual method I get the previous value instead. It happens whether the value is a primitive type (like string) or an object or array.

I've tried to simplify showing this off in the following StackBlitz:
https://stackblitz.com/edit/ngx-sub-form-initial-next

The 4 forms are to show the different scenarios I figured would experience this problem, 2 with NgxAutomaticRootFormControl and 2 with NgxRootFormControl, each having a version for an array object as value and a string as value.

In app.component.ts, I have a variable called doInitialNext. If it is false, no initial value is set and even going back to the null value of each select still emits the correct output. But when set to true (as the example is set to), the value sent from ngAfterViewInit is not emitted either automatically or manually when it is selected again later.

One other thing to note is that overriding emitInitialValueOnInit to true in any of the form components has no effect on this.

If this isn't a bug in ngx-sub-form, then I'd like to know what I'm doing wrong (and perhaps the blog post should be edited to not include that). I've dug a tad into the code, though, and it seems that NgxRootFormComponent's dataInputUpdated is never called and the check in its onRegisterOnChangeHook against this.dataInput$.value is part of the problem. Perhaps I'm wrong, though.

Disabled - is not included in formGroupValues

I noticed this.formGroup.value is being used in ngx-sub-form.component.ts rather than this.formGroup.getRawValue().

this.formGroup.value will omit any disabled controls.

Demo - https://stackblitz.com/edit/ngx-sub-form-stepper-form-demo-s5ajvo *
Note how with

secondUnique: new FormControl({value:'1', disabled: true}),

that this is missing from the values.

*copy of original https://stackblitz.com/edit/ngx-sub-form-stepper-form-demo

I would be interested if this is intended behaviour? Note this hasn't come from my own use cases.

Will ngx-sub-form work in a complex senario with mat-stepper and custom conditional validation?

Sorry I wanted to open a new question since this is not about template driven forms this time.

I'm almost convinced to use you lib in my production. Looks very promising.

I have a stackoverflow question will a sub-form also work in that case? ... where I have multiple FormGroups in a FormArray with some validation and stuff. So the sub-form will be somewhere in a mat-step.

And lastly: Here on another SO Question ^_^. I want to make the Subform invalid/ Subform inputs when the Custom Input Component Validation "fails" (is invalid).

I know the parent form will be invalid if subform is, but is the opposite also possible with your library.

This means subform inputs will be INVALID when the parent element is.

Thank you for the time you spend already answering me!

Used Angular hooks should be mentioned to avoid override

You're using the ngOnInit hook in the parent class, and ngOnDestroy further up. If I too want to use them then that will overwrite yours. In this case I have to call super.ngOnInit()/super.ngOnDestroy() explicitly to make it work. Please emphasize this in the README.

	public ngOnInit(): void {
		super.ngOnInit();
	}

	public ngOnDestroy(): void {
		super.ngOnDestroy();
	}

How can we propagate formGroup.reset() to every subform.

Hello all <3,

here I forked a Stackblitz of yours.

When we click on the RED reset-button. The root-Forms values are being cleared but the values in the subforms still remain.

How can we reset() the whole thing?
Should the root level form and all subforms be in total sync? two-way-bindings?
Should a new method propagateReset() be introduced? That resets itself and all sub-forms down the tree.

`formControlNames` returns array when control is array type

In the readme, if you change

  <div
    class="crew-member"
    formArrayName="crewMembers"
    *ngFor="let crewMember of formGroupControls.crewMembers.controls; let i = index"
  >

to

  <div
    class="crew-member"
    [formArrayName]="formControlNames.crewMembers" 
    *ngFor="let crewMember of formGroupControls.crewMembers.controls; let i = index"
  >

An error is thrown

Updates to form value not appearing in sub form - change detection issue?

I ran into a situation where I was updating the form value but the value wasn't appearing in the sub-form Turned out, I was updating the same object reference as ngx-sub-form had in it's formGroup.value. Therefore in the dataInput pipe, the call to isEqual was returning true and the subform wasn't being updated.

My workaround is to update the value with JSON.parse(JSON.stringify(obj)).

It seems like a bit of a hack...

So the question is, can you please make an example in the documentation of how to deal with updating individual fields of a model?

Allow partial FormGroup

Would this be a valuable feature?

Starting point:

export class ValueComponent extends NgxSubFormComponent<Value> {
  private value: Value;

  protected formControls: Controls<Value> = {
    id: new FormControl(),
    name: new FormControl(),
    value: new FormControl(),
    multiplicity: new FormControl(),
    type: new FormControl()
  };

  writeValue(value: Value): void {
    this.value = value;
    super.writeValue(value);
  }
}

Problem: I don't need to manage all these fields using a FormGroup.
I only need value to be synchronized automatically.
The other static values will be taken via this.value

writeValue(value: Value): void {
  this.value = value;
  super.writeValue(value);
}

Result:

export class ValueComponent extends NgxSubFormComponent<Pick<Value, 'value'>> {
  private value: Value;

  protected formControls: Controls<Pick<Value, 'value'>> = {
    value: new FormControl()
  };
  ...

You can see I've used Pick to choose a subset of the available fields.

Currently an error is thrown here

public writeValue(obj: any): void {
  if (obj) {
    if (!!this.formGroup) {
      this.handleFormArrayControls(obj);

      this.formGroup.setValue(this.transformToFormGroup(obj), {   <--- Here
        emitEvent: false,
      });

because, obviously, the setValue acts only on

{
   value: FormControl
}

while obj is

{
    id: ...,
    name: ...,
    value: ...,
    multiplicity: ...,
    type: ...
} 

The local FormGroup doesn't have all the other FormControls for the properties of obj.

Typing issues in the newest angular 9 preview

There are typing related compilation errors with Ivy. With the most strict typescript settings:

		"noImplicitAny": true,
		"noImplicitReturns": true,
		"noImplicitThis": true,
		"noUnusedParameters": true,
		"strictNullChecks": true,
		"strictFunctionTypes": true,
		"strictPropertyInitialization": true,
ERROR in src/.../forms/contact-form.component.html:1:7 - error TS2322: Type 'TypedFormGroup<ContactForm>' is not assignable to type 'FormGroup | undefined'.
  Type 'TypedFormGroup<ContactForm>' is missing the following properties from type 'FormGroup': _parent, _asyncValidationSubscription, _updateAncestors, _setInitialStatus, and 4 more.

1 <form [formGroup]="formGroup">
src/.../forms/contact-form.component.html:31:12 - error TS2322: Type 'AbstractControl' is not assignable to type 'FormControl'.

31                      <input [formControl]="formGroupControls.email" type="text" name="email" placeholder="Email" />
                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~0m

The `disabled` attribute does not work on a top level form which is an array

Trying to get the top level form disabled in the following case (where currentStateRotors is an array):

<app-rotors-form
  *ngIf="(currentStateRotors$ | async) as currentStateRotors"
  [rotors]="currentStateRotors"
  [disabled]="true"
></app-rotors-form>

The disabled property is not taken into account.

It should loop over the array and disable all the controls from the array.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.