D555
D555

Reputation: 1850

Angular - cannot iterate over array

I am trying to iterate over array but not able to do so (its an array under array). It gives an error:

TypeError: Cannot read property 'toUpperCase' of undefined ("

I am not using toUpperCase anywhere.

The typescript code is :

ngOnInit() {
      this.data = [
          {
              'name': 'Task 1',
              'to_do': ['ToDo1', 'ToDo2', 'ToDo3']
          },
          {
              'name': 'Task 2',
              'to_do': ['ToDo4', 'ToDo5', 'ToDo6']
          }
      ];

  }

The template code is:

<div class="col-md-12">
        Create New Task: <input type="text" name="task" />

        <ul>
          <li *ngFor="let task of data; let i=index; let todo=task.to_do;">
            <div>
              {{ task.name }}
              {{ todo }}
            </div>
            <div *ngFor="let do of todo">
              <input type="text" name="to_do" value="{{ do }}" />
            </div>
          </li>
        </ul>
      </div>

Upvotes: 0

Views: 267

Answers (1)

David
David

Reputation: 34445

It's actually a template parsing error caused by let todo=task.to_do;

You can only declare local variables for ngFor's exported values (index, odd, even, ...)

https://angular.io/api/common/NgForOf#local-variables

Try this

    <ul>
      <li *ngFor="let task of data; let i=index; ">
        <div>
          {{ task.name }}
          {{ task.to_do}}
        </div>
        <div *ngFor="let do of task.to_do">
          <input type="text" name="to_do" value="{{ do }}" />
        </div>
      </li>
    </ul>

Note: There is an $implicit value exported by ngFor, which equals to the current item in the loop. However, the following does not work (I think it can only evaluate simple assignments

 <li *ngFor="let task of data; let i=index; let todo=$implicit.to_do;">

However,it will work using the ng-template form of ngFor, with the let-variable syntax (but it's more verbose)

        <ng-template ngFor let-todo=$implicit.to_do let-task [ngForOf]="data" let-i="index" >
  <li>
  <div>
              {{ task.name }}
              {{ todo }}
            </div>
            <div *ngFor="let do of todo">
              <input type="text" name="to_do" value="{{ do }}" />
            </div>
            </li>
  </ng-template>

Here is a stackblitz showing both ways

https://stackblitz.com/edit/angular-cces4g?file=app%2Fapp.component.html

Upvotes: 3

Related Questions