-1

enter image description here> ## app.component.ts ##

When click on SAve Button, I get error, ERROR TypeError: Cannot read property 'value' of undefined

When passing addRow(name.value) in second row it worked fine. But, when I pass it is first row as saveRow(name.value).!!! ERROR TypeError: Cannot read property 'value' of undefined.....................I also tried saveRow(name) than error doesnot come but value passed is undefined!

<div class="container">
    <div class="row">
        <form [formGroup]="form1">
            <div class="form-group">
                <table class="table">
                    <thead>
                        <tr>
                            <td>S.No</td>
                            <td>NAME</td>
                            <td>WEIGHT(in grams)</td>
                            <td>QUANTITY</td>
                        </tr>
                    </thead>
                    <tbody>
                        <tr *ngFor="let i of form1.get('id').value; let k = index">
                            <td>
                                <ng-container *ngIf="tempindex !== k">{{ form1.get('id').value[k] }}</ng-container>
                            </td>
                            <td>
                                <ng-container *ngIf="tempindex !== k">{{ form1.get('name').value[k] }}</ng-container>
                                <input type="text" *ngIf="tempindex === k" [value]="form1.get('name').value[k]" #name>
                            </td>
                            <td>
                                <ng-container *ngIf="tempindex !== k">{{ form1.get('weight').value[k] }}</ng-container>
                                <input type="text" *ngIf="tempindex === k" [value]="form1.get('name').value[k]" #weight>
                            </td>
                            <td>
                                <ng-container *ngIf="tempindex !== k">{{ form1.get('quantity').value[k] }}</ng-container>
                                <input type="text" *ngIf="tempindex === k" [value]="form1.get('quantity').value[k]" #quantity>
                            </td>
                            <td>
                                <ng-container *ngIf="tempindex === k">
                                    <button *ngIf="editclicked" class="btn btn-primary" (click)="saveRow(k, name.value, weight.value, quantity.value)">Save</button>
                                </ng-container>

                                <button *ngIf="!editclicked" class="btn btn-primary" (click)="editRow(k)">Edit</button> &nbsp;&nbsp;
                                <button *ngIf="!editclicked" class="btn btn-danger" (click)="delRow(k)">Delete</button>
                            </td>
                        </tr>
                        <button *ngIf="!addclicked" class="btn btn-default" (click)="addRow()">ADD</button>
                        <tr *ngIf="addclicked">
                            <td></td>
                            <td>
                                <input type="text" #name>
                            </td>
                            <td>
                                <input type="text" #weight>
                            </td>
                            <td>
                                <input type="text" #quantity>
                            </td>
                            <td><button class="btn btn-primary" (click)="hitadd(name.value, weight.value, quantity.value)">Add</button>&nbsp;&nbsp;
                                <button class="btn btn-danger" (click)="hitcancel()">Cancel</button>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </form>
    </div>
</div>

app.component.html

First tr is used to fetch all fields from FormArrays

Second tr is used to add new data to the FormArrays (Problem!!!)

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormArray } from '@angular/forms'
import { element } from 'protractor';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'app';
  form1: FormGroup;
  addclicked = false;
  tempId = '';
  tempindex;
  editclicked = false;

  ngOnInit() {
    this.form1 = new FormGroup({
      'id': new FormArray([]),
      'name': new FormArray([]),
      'weight': new FormArray([]),
      'quantity': new FormArray([])
      
      
      // 'id': new FormArray([new FormControl('1'), new FormControl('2')]),
      // 'name': new FormArray([new FormControl('Beans'), new FormControl('Soup')]),
      // 'weight': new FormArray([new FormControl('100'), new FormControl('125')]),
      // 'quantity': new FormArray([new FormControl('60'), new FormControl('20')])

    });
  }
  addRow(){
    this.addclicked = true;
    this.tempId = '';
  }
  hitcancel(){
    this.addclicked = false;
    this.tempId = '';
  }
  hitadd(name, weight, quantity){
    this.tempId = (this.ids.value.length + 1).toString(10);

    this.ids.push(new FormControl(this.tempId));
    this.names.push(new FormControl(name));
    this.weights.push(new FormControl(weight));
    this.quantities.push(new FormControl(quantity));
    
    this.tempId = '';
    this.addclicked = false;

  }

  editRow(index: number){
    this.editclicked = true;
    this.tempindex = index;
    
    //this.ids.at(index).patchValue(null);
  }

  saveRow(index, name, weight, quantity){
    this.editclicked = false;
    this.tempindex = undefined;
    console.log(name);
    // console.log(this.names.at(index).setValue(name));
    // this.weights.at(index).setValue(weight);
    // this.quantities.at(index).setValue(quantity);
  }

  delRow(index: number){
    this.addclicked = false;
    
    this.ids.removeAt(index);
    this.names.removeAt(index);
    this.weights.removeAt(index);
    this.quantities.removeAt(index);

    let i = 0;
    this.ids.controls.forEach(element => {
      i++;
      element.setValue(i.toString(10))
    });
  }
  get ids(){
    return this.form1.get('id') as FormArray;
  }
  get names(){
    return this.form1.get('name') as FormArray;
  }
  get weights(){
    return this.form1.get('weight') as FormArray;
  }
  get quantities(){
    return this.form1.get('quantity') as FormArray;
  }
}
<!-- end snippet -->
Community
  • 1
  • 1
  • could you please show what error you are getting with this code setup? – amal Sep 27 '17 at 12:56
  • I have added a image above of output. As, there is no error!.... Could you please, clone this repository and check what is the problem? https://github.com/RishabhSaluja/ang – RISHABH SALUJA Sep 27 '17 at 13:03
  • Just see the difference between the Empty FormArray and the Predefined FormArray part, – RISHABH SALUJA Sep 27 '17 at 13:06
  • I want first to display element only if formarray is not empty. But, I have already implemented ngFor in so i cannot add ngif. So, it is displaying the 1 row by default.....,....I want my second to push elements after the index of pre-defined FormArray length. – RISHABH SALUJA Sep 27 '17 at 14:24

1 Answers1

0

I have updated the above code but emitting non-important element according to my prospective. Please take a look.

These are the modifications:

app.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormArray } from '@angular/forms'
import { element } from 'protractor';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'app';
  form1: FormGroup;
  addclicked = false;
  tempId = '';

  ngOnInit() {
    this.form1 = new FormGroup({
      'id': new FormArray([]),
      'name': new FormArray([]),
      'weight': new FormArray([]),
      'quantity': new FormArray([])

      // 'id': new FormArray([new FormControl('1'), new FormControl('2')]),
      // 'name': new FormArray([new FormControl('Beans'), new FormControl('Soup')]),
      // 'weight': new FormArray([new FormControl('100'), new FormControl('125')]),
      // 'quantity': new FormArray([new FormControl('60'), new FormControl('20')])

    });
  }
  addRow(){
    this.addclicked = true;
    this.tempId = '';
  }
  hitcancel(){
    this.addclicked = false;
    this.tempId = '';
  }

  hitadd(name, weight, quantity){
    this.tempId = (this.ids.value.length + 1).toString(10);

    this.ids.push(new FormControl(this.tempId));
    this.names.push(new FormControl(name));
    this.weights.push(new FormControl(weight));
    this.quantities.push(new FormControl(quantity));

    this.tempId = '';
    this.addclicked = false;
  }

  editRow(index: number){
  }

  delRow(index: number){
    this.ids.removeAt(index);
    this.names.removeAt(index);
    this.weights.removeAt(index);
    this.quantities.removeAt(index);

    let i = 0;
    this.ids.controls.forEach(element => {
      i++;
      element.setValue(i.toString(10))
    });
  }
  get ids(){
    return this.form1.get('id') as FormArray;
  }
  get names(){
    return this.form1.get('name') as FormArray;
  }
  get weights(){
    return this.form1.get('weight') as FormArray;
  }
  get quantities(){
    return this.form1.get('quantity') as FormArray;
  }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule

  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.html

<div class="container">
<div class="row">
    <form [formGroup]="form1">
        <div class="form-group">
            <table class="table">
                <thead>
                    <tr>
                        <td>S.No</td>
                        <td>NAME</td>
                        <td>WEIGHT(in grams)</td>
                        <td>QUANTITY</td>
                    </tr>
                </thead>
                <tbody>
                    <tr *ngFor="let i of form1.get('id').value; let k = index">
                        <td>{{ form1.get('id').value[k] }}</td>
                        <td>{{ form1.get('name').value[k] }}</td>
                        <td>{{ form1.get('weight').value[k] }}</td>
                        <td>{{ form1.get('quantity').value[k] }}</td>
                        <td><button class="btn btn-primary" (click)="editRow(k)">Edit</button>&nbsp;&nbsp;<button class="btn btn-danger"
                                (click)="delRow(k)">Delete</button></td>
                    </tr>
                    <button *ngIf="!addclicked" class="btn btn-default" (click)="addRow()">ADD</button>
                    <tr *ngIf="addclicked">
                        <td></td>
                        <td>
                            <input type="text" #name>
                        </td>
                        <td>
                            <input type="text" #weight>
                        </td>
                        <td>
                            <input type="text" #quantity>
                        </td>
                        <td><button class="btn btn-primary" (click)="hitadd(name.value, weight.value, quantity.value)">Add</button>&nbsp;&nbsp;
                            <button
                                class="btn btn-danger" (click)="hitcancel()">Cancel</button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>
    </form>
</div>


In light of the code modifications that you have undergone, try to see if this fixes the error you are getting,

<td>
                                <ng-container *ngIf="tempindex !== k">{{ form1.get('id').value[k] }}</ng-container>
                            </td>
                            <td>
                                <ng-container *ngIf="tempindex !== k">{{ form1.get('name').value[k]}}</ng-container>
                                <input type="text" *ngIf="tempindex === k" [value]="form1.get('name').value[k]" #nameEdit>
                            </td>
                            <td>
                                <ng-container *ngIf="tempindex !== k">{{ form1.get('weight').value[k] }}</ng-container>
                                <input type="text" *ngIf="tempindex === k" [value]="form1.get('name').value[k]" #weightEdit>
                            </td>
                            <td>
                                <ng-container *ngIf="tempindex !== k">{{ form1.get('quantity').value[k] }}</ng-container>
                                <input type="text" *ngIf="tempindex === k" [value]="form1.get('quantity').value[k]" #quantityEdit>
                            </td>
                            <td>
                                <ng-container *ngIf="tempindex === k">
                                    <button *ngIf="editclicked" class="btn btn-primary" (click)="saveRow(k, nameEdit.value, weightEdit.value, quantityEdit.value)">Save</button>
                                </ng-container>

                                <button *ngIf="!editclicked" class="btn btn-primary" (click)="editRow(k)">Edit</button> &nbsp;&nbsp;
                                <button *ngIf="!editclicked" class="btn btn-danger" (click)="delRow(k)">Delete</button>
                            </td>

In your component,

saveRow(index: number, name, weight, quantity){

    this.names.at(index).setValue(name));
    this.weights.at(index).setValue(weight);
    this.quantities.at(index).setValue(quantity);

    this.editclicked = false;
    this.tempindex = undefined;
  }

module

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

template

<div class="container">
    <div class="row">
        <form [formGroup]="form1">
            <div class="form-group">
                <table class="table">
                    <thead>
                        <tr>
                            <td>S.No</td>
                            <td>NAME</td>
                            <td>WEIGHT(in grams)</td>
                            <td>QUANTITY</td>
                        </tr>
                    </thead>
                    <tbody>
                        <tr *ngFor="let i of form1.get('id').value; let k = index">
                                <td>
                                        <ng-container *ngIf="tempindex !== k">{{ form1.get('id').value[k] }}</ng-container>
                                    </td>
                                    <td>
                                        <ng-container *ngIf="tempindex !== k">{{ form1.get('name').value[k]}}</ng-container>
                                        <input type="text" *ngIf="tempindex === k" [(ngModel)]="tempName" [ngModelOptions]="{standalone: true}">
                                    </td>
                                    <td>
                                        <ng-container *ngIf="tempindex !== k">{{ form1.get('weight').value[k] }}</ng-container>
                                        <input type="text" *ngIf="tempindex === k" [(ngModel)]="tempWeight" [ngModelOptions]="{standalone: true}">
                                    </td>
                                    <td>
                                        <ng-container *ngIf="tempindex !== k">{{ form1.get('quantity').value[k] }}</ng-container>
                                        <input type="text" *ngIf="tempindex === k" [(ngModel)]="tempQuantity" [ngModelOptions]="{standalone: true}">
                                    </td>
                                    <td>
                                        <ng-container *ngIf="tempindex === k">
                                            <button *ngIf="editclicked" class="btn btn-primary" (click)="saveRow(k, tempName, tempWeight, tempQuantity)">Save</button>
                                        </ng-container>

                                        <button *ngIf="!editclicked" class="btn btn-primary" (click)="editRow(k)">Edit</button> &nbsp;&nbsp;
                                        <button *ngIf="!editclicked" class="btn btn-danger" (click)="delRow(k)">Delete</button>
                                    </td>
                        </tr>
                        <button *ngIf="!addclicked" class="btn btn-default" (click)="addRow()">ADD</button>
                        <tr *ngIf="addclicked">
                            <td></td>
                            <td>
                                <input type="text" #name>
                            </td>
                            <td>
                                <input type="text" #weight>
                            </td>
                            <td>
                                <input type="text" #quantity>
                            </td>
                            <td><button class="btn btn-primary" (click)="hitadd(name.value, weight.value, quantity.value)">Add</button>&nbsp;&nbsp;
                                <button class="btn btn-danger" (click)="hitcancel()">Cancel</button>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </form>
    </div>
</div>

component

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormArray } from '@angular/forms'
import { element } from 'protractor';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'app';
  form1: FormGroup;
  addclicked = false;
  tempId = '';
  tempName = '';
  tempWeight = '';
  tempQuantity = '';
  tempindex;
  editclicked = false;

  ngOnInit() {
    this.form1 = new FormGroup({
      'id': new FormArray([]),
      'name': new FormArray([]),
      'weight': new FormArray([]),
      'quantity': new FormArray([])


      // 'id': new FormArray([new FormControl('1'), new FormControl('2')]),
      // 'name': new FormArray([new FormControl('Beans'), new FormControl('Soup')]),
      // 'weight': new FormArray([new FormControl('100'), new FormControl('125')]),
      // 'quantity': new FormArray([new FormControl('60'), new FormControl('20')])

    });
  }
  addRow(){
    this.addclicked = true;
    this.tempId = '';
  }
  hitcancel(){
    this.addclicked = false;
    this.tempId = '';
  }
  hitadd(name, weight, quantity){
    this.tempId = (this.ids.value.length + 1).toString(10);

    this.ids.push(new FormControl(this.tempId));
    this.names.push(new FormControl(name));
    this.weights.push(new FormControl(weight));
    this.quantities.push(new FormControl(quantity));

    this.tempId = '';
    this.addclicked = false;

    console.log(this.form1);
  }

  editRow(index: number) {
    this.tempName = this.names.value[index];
    this.tempWeight = this.weights.value[index];
    this.tempQuantity = this.quantities.value[index];
    this.editclicked = true;
    this.tempindex = index;

    //this.ids.at(index).patchValue(null);
  }

  saveRow(index: number, name, weight, quantity){

        this.names.at(index).setValue(name);
        this.weights.at(index).setValue(weight);
        this.quantities.at(index).setValue(quantity);

        this.editclicked = false;
        this.tempindex = undefined;
      }

  delRow(index: number){
    this.addclicked = false;

    this.ids.removeAt(index);
    this.names.removeAt(index);
    this.weights.removeAt(index);
    this.quantities.removeAt(index);

    let i = 0;
    this.ids.controls.forEach(element => {
      i++;
      element.setValue(i.toString(10))
    });
  }
  get ids(){
    return this.form1.get('id') as FormArray;
  }
  get names(){
    return this.form1.get('name') as FormArray;
  }
  get weights(){
    return this.form1.get('weight') as FormArray;
  }
  get quantities(){
    return this.form1.get('quantity') as FormArray;
  }
}

This one works. Please remove unwanted contented from the code here if you like. Just showing it fully here for now.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
amal
  • 3,140
  • 1
  • 13
  • 20
  • See [this](https://angular.io/api/forms/NgModel#options) to learn more on ngModelOptions. `ngModel` can be used irrespective of whether the form is reactive/template-driven for implementing 1-way or 2-way binding. When you use it on a template-driven form (initialized with #myForm="ngForm"), then your ngModel containing control should also need a `name` attribute for it work properly as a control. When you use it in a reactive form for binding reasons (you can have other ways to create binding, but this is out of the box easy), you don't necessarily need a `name` attribute with it. – amal Sep 28 '17 at 14:24
  • The `standalone: true` indicates that this is simply used as a standalone control (for binding reasons as you rightly guessed) and not being part of any forms this element might be part of in the template. Thus the form encapsulating this element will not have the controls of this individual element added to the main form's control. – amal Sep 28 '17 at 14:27
  • "this.ids.controls.forEach(element =>?? working??" - what is the question about this? Didn't understand. – amal Sep 28 '17 at 14:28
  • I used the temp-related variables in the component, seeing you might need it when you have to 'Edit' rows in a random fashion. Currently, for adding, the row always appear at the end. But when it comes to editing a random row anywhere on the list, depending on how you implement it of course, you might require such a variable to assign the row values and clear them once editing is over (so that you could reuse). But of course you could find others ways of doing it as well. Might have confused you, my bad, should have answered only the question that was asked :) – amal Sep 28 '17 at 14:31
  • can you check update, for this error: ERROR TypeError: Cannot read property 'value' of undefined – RISHABH SALUJA Sep 28 '17 at 14:38
  • I don't see a variable for `name1`. Then how can it have a value. The error is pretty obvious? – amal Sep 28 '17 at 15:27
  • it is id of input tag – RISHABH SALUJA Sep 28 '17 at 15:27
  • See, I used `name.value` where the `name` was the template reference variable assigned in ``. Since you haven't specified any `#name1` anywhere, it is normal that the error appears – amal Sep 28 '17 at 15:30
  • It cannot be an `id` of `input`, has to be a template reference variable which, in my case is an `` element which is of type HTMLInputElement that has a property 'value', hence I could access that 'value' of HTMLInputElement by referring to its reference variable, here `#name` (without the hash symbol #), `name.value`. Hope it makes sense. – amal Sep 28 '17 at 15:31
  • I changed to name.value, Still the same error,.... ERROR TypeError: Cannot read property 'value' of undefined at Object.eval – RISHABH SALUJA Sep 28 '17 at 15:41
  • It depends on the logic on your template. Can I see your current template and where exactly it fails? – amal Sep 28 '17 at 15:42
  • Updated the code,See above!! I want to pass the updated input fields to function ... saveRow(index: number, name, weight, quantity){ this.names.at(index).setValue(name)); this.weights.at(index).setValue(weight); this.quantities.at(index).setValue(quantity); } – RISHABH SALUJA Sep 28 '17 at 15:46
  • why are you using the same `#name`, `#weight` and `#quantity` template reference variables used for Add-ing in the Save-ing/Edit-ing logic? Are you making edits to the same input fields used in Adding a new row? The logic doesn't make sense. – amal Sep 28 '17 at 15:57
  • let i = 0; this.ids.controls.forEach(element => { i++; element.setValue(i.toString(10)) }); .....................Explain the working of this – RISHABH SALUJA Sep 28 '17 at 17:42
  • That's why I reserved the temp-variables earlier for future purposes of when you work with the Edit/Save logic – amal Sep 28 '17 at 17:42
  • That is to re assign the Id values to the rows, otherwise if you delete one of the rows in between, then the new list will have the Ids not in ascending order. Say if you removed 2 row from a list of 3 rows, then the new list of rows will have Ids 1 and 3 instead of 1 and 2. If you don't want that behaviour and would like to keep the original Ids, then you can remove that logic. – amal Sep 28 '17 at 17:45
  • There are many ways of achieving things in angular. We all code with our abilities and knowledge. So as long as it makes sense for you to go with it, let it flow and should be right :) – amal Sep 28 '17 at 17:46
  • How come (name.value) is working below but not above? – RISHABH SALUJA Sep 28 '17 at 17:47
  • Yeah, that was the tricky part. Since you are using an `ngIf` on that `input` element directly, I think it was messing up the registering of that template reference variable someway. – amal Sep 28 '17 at 17:50
  • check out [this for more info](https://stackoverflow.com/a/44812573/5260710). Hope it helps – amal Sep 28 '17 at 17:55
  • If, create components of my project, how I can update formgroup of parent component when i add, delete elements. – RISHABH SALUJA Sep 30 '17 at 05:48
  • @Output() updateData1 = new EventEmitter({**how to pass FormGroup here**})<>(); Any Idea!!!!!!! – RISHABH SALUJA Sep 30 '17 at 13:51
  • Could you please post this as a separate question? I understand that you are working on an app, but the different scenarios that produces an error for you might be due to different reasons. Stack overflow is a platform for getting answers to problems for the person posting it but at the same time it also is a future reference for people coming across such problems. Hence if you bundle all your questions in one post from time to time, it doesn't help with this purpose. It might also mutate the original question and its answer in doing so. Hope it makes sense :) – amal Sep 30 '17 at 14:36
  • similar question is already posted by 2 persons but no solutions. So, that's why I am not posting the question again and as I am shifting to components. So, the app is quite messed up. – RISHABH SALUJA Sep 30 '17 at 14:39
  • Question might be the same. But the scenario might be different. Even though it looks similar just by looking at the question, in the description you can always find differences in implementation one way or other. If you post your question with your specific scenario, then that might look like the same but will be your question. If SO finds it duplicate, somebody will direct you to the right links where an answer is provided. Otherwise someone will answer it for you. By posting questions (in the right way/format) you are also contributing to SO. It's not just the answers that matter. – amal Sep 30 '17 at 14:44
  • wait posting it! search for any other errors also in my code! – RISHABH SALUJA Sep 30 '17 at 14:46
  • https://stackoverflow.com/questions/46503942/want-to-pass-formgroup-of-4-formarrays-in-emitter-function !!!!!!!!!!!!!!!!!!! Comment please whenever you see it – RISHABH SALUJA Sep 30 '17 at 15:02