UncleFester
UncleFester

Reputation: 417

How to use reactive forms inside ng-template

I have just started with Angular 4 and I need to develop a CRUD grid, where the user can add, edit or delete rows.

During my research I found this article where it shows how to create the grid and also the actions: Angular 4 Grid with CRUD operations.

Looking at his code, what called my attention was the way he is using the ng-template to toggle between edit/view mode.

<tr *ngFor="let emp of EMPLOYEES;let i=idx">
 <ng-template [ngTemplateOutlet]="loadTemplate(emp)" [ngOutletContext]="{ $implicit: emp, idx: i }"></ng-template>
</tr>

On the article he uses template driven forms to edit the row. However, I was trying to change to reactive forms.

In my attempt to do that, I tried to replace the [(ngModel)] to formControlName and I got some errors. My first attempt I tried to add the [formGroup] at the beginning of the template html inside form element. But when I tried to run and edit the row, I got the following error:

Error: 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).

When I tried to move the [formGroup] inside the ng-template it works, however I was not able to bind the value to the fields and I had to set the values in the loadTemplate function:

loadTemplate(emp: Employee) {
    if (this.selemp && this.selemp.id === emp.id) {

        this.rForm.setValue({
            id: emp.id,
            name: emp.name
        });

        return this.editTemplate;
    } else {
        return this.readOnlyTemplate;
    }
}

This works and show the values inside the fields in a read only mode :(

Here is the Plunker of what I have got so far.

How can I make a reactive form work with ng-template and how to set values to edit the entries?

Any help is appreciated! Thanks

Upvotes: 6

Views: 5597

Answers (1)

AVJT82
AVJT82

Reputation: 73337

Actually your form is not readonly, you are just constantly overwriting the input you are entering. Since you are having a method call in template (which is usually not a good idea), loadTemplate gets called whenever changes happen, which in it's turn means that

this.rForm.setValue({
   id: emp.id,
   name: emp.name
});

gets called over and over whenever you try and type anything. We can overcome this with instead setting the form values when you click to edit. Here we also store the index so that we can use it to set the modified values in the correct place in array, utilizing the index could perhaps be done in a smarter way, but this is a quick solution to achieve what we want.

editEmployee(emp: Employee) {
    this.index = this.EMPLOYEES.indexOf(emp) 
    this.selemp = emp;
    this.rForm.setValue({
      id: emp.id,
      name: emp.name
    });
}

so when we click save, we use that index...

saveEmp(formValues) {
  this.EMPLOYEES[this.index] = formValues;
  this.selemp = null;
    this.rForm.setValue({
      id: '',
      name: ''
    });

}

Your plunker: https://plnkr.co/edit/6QyPmqsbUd6gzi2RhgPp?p=preview

BUT notice...

I would suggest you perhaps rethink this idea, having the method loadTemplate in template, will cause this method to fire way too much. You can see in the plunker, where we console log fired! whenever it is fired, so it is a lot! Depending on the case, this can cause serious performance issues, so keep that in mind :)

PS. Made some other changes to code for adding a new employee to work properly (not relevant to question)

Upvotes: 2

Related Questions