Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 552
UncleFester Avatar asked Aug 17 '17 18:08

UncleFester


People also ask

Can we use ngModel with reactive forms?

You can use [(ngModel)] with Reactive forms. This will a completely different directive than the one that would be used without the formControlName . With reactive forms, it will be the FormControlNameDirective . Without the formControlName , the NgModel directive would be used.

Can we use ngModel and formControlName together?

In short ngModel can't be used by itself within FormGroup When you use formControlName, ngModel does not activate or create a control (it's simply used as an @Input). formControlName just links to the existing input you created in your class.

Should I use reactive forms or template forms?

Template Driven Forms are based only on template directives, while Reactive forms are defined programmatically at the level of the component class. Reactive Forms are a better default choice for new applications, as they are more powerful and easier to use.

Can we use ngModel in template driven forms?

The ngModel directive declared in the FormsModule lets you bind controls in your template-driven form to properties in your data model.


1 Answers

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)

like image 138
AT82 Avatar answered Oct 19 '22 10:10

AT82