Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FormArray usecase #9

Closed
lppedd opened this issue Mar 15, 2019 · 13 comments · Fixed by #65
Closed

FormArray usecase #9

lppedd opened this issue Mar 15, 2019 · 13 comments · Fixed by #65
Assignees
Labels

Comments

@lppedd
Copy link
Contributor

lppedd commented Mar 15, 2019

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

@maxime1992 maxime1992 changed the title [not-an-issue] FormArray usecase FormArray usecase Mar 15, 2019
@maxime1992 maxime1992 self-assigned this Mar 17, 2019
@maxime1992
Copy link
Collaborator

Hi @lppedd,

thanks for the kind words.

@zakhenry and I discussed a bit about that and came to the conclusion that yes we haven't properly shown how to handle that use case.

I'm trying to come up with an example (see #10), hopefully this could help you understand better how to handle a FormArray value 😃.

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

I started from that and tried to implement it. It's still a WIP but I think the biggest part of the work is done already.

I still need to discuss with @zakhenry to see if everything makes sense and if it's the best approach because I'd break it down into sub components normally which I have not (yet?) done to show how to directly use a FormGroup.

Feel free to take a look to the PR and comment out what's on the top of your head while looking at the implementation :).

@lppedd
Copy link
Contributor Author

lppedd commented Mar 18, 2019

@maxime1992 thank you for the quick example!

I've given a look at it and it seems pretty straightforward. Prior to submit this question the (non-working) solution I had tried to implement was almost like that, so no particular notes!
The only thing that feels more "complex" is the direct access to the underlying FormGroup for the *ngFor directive.

return this.formGroup.get(this.formControlNames.colors) as FormArray

But I think that's inevitable.

This part of your message got me curious

I'd break it down into sub components normally

Could you expand on that?
Again, thank you.

Btw, I gave it a try, with your fix, and it seems okay.

@lppedd
Copy link
Contributor Author

lppedd commented Mar 18, 2019

@maxime1992 just noticed I cannot have a FormArray in the "first-level" Component. Is that by design/wanted?

Nevermind, figured it out, I have to use formArray.push(value) when building the outmost Controls<Type> (passing by the internal FormGroup).

@AdditionAddict
Copy link

AdditionAddict commented Jun 16, 2019

I'm trying to use ngx-sub-form to convert this stackblitz:
https://stackblitz.com/edit/angular-author-book-chapter-demo-rvk27f0
into something more manageable.

It's based on the answer to this SO question https://stackoverflow.com/questions/54532104/angular-7-reactive-form-slow-response-when-has-large-data

I get error If you need to pass an array, please wrap it (for now) using "NgxSubFormRemapComponent" into an "array" property for example. Track direct array support here #9

How I'm supposed to implement NgxSubFormRemapComponent in this case of a FormArray? Is there a simple example if this I could use?

Edit: another version passing formgroups to subcomponents directly https://stackblitz.com/edit/angular-author-book-chapter-demo-rvk27f0-separate

@maxime1992
Copy link
Collaborator

Hi @AdditionAddict,

another version passing formgroups to subcomponents directly https://stackblitz.com/edit/angular-author-book-chapter-demo-rvk27f0-separate

I've just finished to write a blog post about how to manage complex forms and I'm explaining there why passing a formGroup as an input is in my opinion not a good idea. I'll let you go through the article if you want to know more https://dev.to/maxime1992/building-scalable-robust-and-type-safe-forms-with-angular-3nf9

About your example, I've been trying to build it and yes I'm also stuck with the array.

I planned to get back on that issue a week or two ago but a PR was pending (CF #41) and I didn't want to start a new one until that one was done. I guess it can/will be prioritised now :)

I'll come back to you as soon as the work is done with a demo for your example 👍

@maxime1992
Copy link
Collaborator

Small update:

I've got a prototype running and I think it's on a good way 🙌.
I need to discuss a few things with @zakhenry first but I think we can get that feature in this week.

@AdditionAddict I've used your example (as a light version) for my test. Here's how it'd look like with authors:

authors-form.component.ts

interface AuthorForm {
  authors: Author[];
}

@Component({
  selector: 'app-authors-form',
  templateUrl: './authors-form.component.html',
  styleUrls: ['./authors-form.component.scss'],
})
export class AuthorsFormComponent extends NgxRootFormComponent<
  Author[],
  AuthorForm
> {
  @DataInput()
  @Input('authors')
  public dataInput: Author[] | null | undefined;

  @Output('authorsUpdated')
  public dataOutput: EventEmitter<Author[]> = new EventEmitter();

  protected getFormControls(): Controls<AuthorForm> {
    return {
      authors: new FormArray([]),
    };
  }

  protected transformToFormGroup(obj: Author[] | null): AuthorForm {
    return { authors: obj };
  }

  protected transformFromFormGroup(formValue: AuthorForm): Author[] | null {
    return formValue.authors;
  }

  public addAuthor() {
    this.formGroupControls.authors.push(new FormControl());
  }
}

authors-form.component.html

<form [formGroup]="formGroup">
  <ng-container
    formArrayName="authors"
    *ngFor="let author of formGroupControls.authors.controls; let i = index"
  >
    <app-author-form [formControl]="author"></app-author-form>
  </ng-container>
</form>

<button (click)="addAuthor()">Add author</button>

author-form.component.ts

@Component({
  selector: 'app-author-form',
  templateUrl: './author-form.component.html',
  styleUrls: ['./author-form.component.scss'],
  providers: subformComponentProviders(AuthorFormComponent),
})
export class AuthorFormComponent extends NgxSubFormComponent<Author> {
  protected getFormControls(): Controls<Author> {
    return {
      name: new FormControl(),
    };
  }
}

author-form.component.html

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

Hopefully you might find that easier to read than the one you originally provided 😄

Let me know!

maxime1992 added a commit that referenced this issue Jun 17, 2019
@AdditionAddict
Copy link

Thanks for the quick reply! I had a go using this last night and managed to get the Author array working as you describe. For the next level (Author with multipe Books) should I be using NgxSubFormRemapComponent or keep to NgxSubFormComponent? Do is need to isolate the form array (books) to it's own formarray only component? I'll have another go today (I'm slow) and see if I can get this working.

@maxime1992
Copy link
Collaborator

@AdditionAddict I've been working yesterday and this morning onto that feature.

I've got a branch here https://github.com/cloudnc/ngx-sub-form/tree/feat/form-array where I'm nearly done but I miss a few tests and a bit of cleanup too.

Can't have a look at that until tonight but I think it'll take me until the end of the week to finish that one up so if you can wait I'd recommend you to, otherwise just clone my branch locally and build the library then use it in your own project like that for a few days. I highly doubt the public API will change it'll be mostly tests and cleanup now. But once again if you can wait a few days it'll be easier and I also have a repro of your demo just waiting that the branch I'm working on is published :)

@maxime1992
Copy link
Collaborator

🎉 This issue has been resolved in version 3.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@maxime1992
Copy link
Collaborator

☝️ sorry that version shouldn't have been 3.0.0 has we've reverted the breaking change.

I've unpublished the version on npm and I'm trying to publish a new one under 2.x

@maxime1992
Copy link
Collaborator

🎉 This issue has been resolved in version 2.11.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@alemputes
Copy link

Hi, what if you want to update just one Author? How do you get the specific author object that was changed in the parent from a subform and only output that author from the parent when using form arrays? Now you are passing back the full array of authors as the output, what if you have a large array of items and you only change one of them then you probably want to only update that specific one on the server and not the full array.

@maxime1992
Copy link
Collaborator

Hi @alemputes, this is not ngx-sub-form responsability.

I'm sure there are a lot of libs on npm to help you get only a diff.

You could then use the pairWise operator for example to compare previous value and current one :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
4 participants