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

Angular messes up immediately nested ngFor <template>s #1653

Closed
pschiffmann opened this issue Oct 31, 2018 · 3 comments

Comments

Projects
None yet
2 participants
@pschiffmann
Copy link

commented Oct 31, 2018

Today I encountered some weird behaviour when I tried to iterate over a list of lists with ngFor, when the outer ngFor loop is not embedded in a structural directive, but explicitly written out as directives on a <template>.
I reproduced the issue in this standalone example component:

import 'dart:math';

import 'package:angular/angular.dart';

@Component(
  selector: 'demo-component',
  template: '''
<div>
  <button (click)="addList()">add list</button>
  <button (click)="addElements()">add elements</button>
</div>
<ul>
<template ngFor let-outer [ngForOf]="lists">
  <li *ngFor="let number of outer">
    {{number}}
  </li>
</template>
</ul>
''',
  directives: [coreDirectives],
)
class DemoComponent {
  final List<List<int>> lists = [
    [1]
  ];

  /// Adds a new inner list to [lists].
  void addList() => lists.add(
      List.generate(lists.first.length, (i) => _valueFor(lists.length, i)));

  /// Adds a new element to each inner list in [lists].
  void addElements() {
    var i = 0;
    for (final inner in lists) {
      inner.add(_valueFor(i++, inner.length));
    }
  }

  int _valueFor(int listIndex, int elementIndex) =>
      (elementIndex + 1) * pow(10, listIndex);
}

By clicking on the two buttons, you can generate a list of lists of numbers of the following pattern:

[
  [1, 2, 3],
  [10, 20, 30],
  [100, 200, 300]
]

The template should render a flattened list, like this:

  • 1
  • 2
  • 3
  • 10
  • 20
  • 30
  • 100
  • 200
  • 300

However, when you add new inner lists (e.g. [1000, 2000, 3000]), the corresponding HTML is rendered at the wrong place – not at the end of the flattened list, but somewhere in the middle. (I haven't figured out the exact pattern where the new nodes are placed. The position changes depending on which button you press first)

I use Angular version 5.0.0, Dart 2.0.0, and Chrome Version 70.0.3538.77.

@leonsenft

This comment has been minimized.

Copy link
Contributor

commented Oct 31, 2018

Thanks for the report. I'm able to reproduce. In fact pressing "Add elements" once, followed by "Add lists" demonstrates an issue immediately.

@leonsenft

This comment has been minimized.

Copy link
Contributor

commented Oct 31, 2018

This is related to having a <template> nested directly beneath another <template> with no intermediate DOM element to serve as the parent of the inner <template>. Your examples works fine if you place the outer ngFor on an HTML element rather than a <template>.

@leonsenft

This comment has been minimized.

Copy link
Contributor

commented Oct 31, 2018

The issue appears to be related to NgFor's iterable diffing algorithm on the outer NgFor. The issue does not occur if the outer NgFor is replaced with an NgForIdentity.

leonsenft added a commit that referenced this issue Nov 1, 2018

fix(Core): fix `AppView.lastRootNode` for nested view containers
When a view container was directly nested inside another, `lastRootNode` would
incorrectly return the last root node of the first nested view container. It now
correctly returns the last root node of the last nested view container.

Fixes #1653.

PiperOrigin-RevId: 219648819

@alorenzen alorenzen closed this in 773ae35 Nov 7, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.