0
votes

I have a problem with the performance of binding data to a table. I started to use core-menu with paper-items. paper-items are supposed to display a nice animation when clicked. It works fine, but if I try to bind some data in the selected index changed handler, the animation frame rate is awful.

Is there anything I can do to improve the frame rate on paper-item?

Here is an example (binds 250 cells in a table).

clickcounter.html

<link rel="import" href="packages/polymer/polymer.html">
<link rel="import" href="packages/core_elements/core_menu.html">
<link rel="import" href="packages/core_elements/core_icons.html">
<link rel="import" href="packages/paper_elements/paper_item.html">

<polymer-element name="click-counter">
  <template>
    <style>
      core-menu {
        color: #01579b;
        margin: 10px 0 0 0;
      }

      core-menu > paper-item {
        transition: all 300ms ease-in-out;
      }

      core-menu > paper-item.core-selected {
        background: #e1f5fe;
      }
    </style>
    <div>
      <core-menu selected="{{selIndex}}">

            <paper-item icon="settings" label="Item 0">
              <a ></a>
            </paper-item>
             <paper-item icon="settings" label="Item 1">
              <a ></a>
            </paper-item>

        </core-menu>
    </div>
    <table>                                
        <thead>
        <tr>
            <th>C1</th>
            <th>C2</th>
            <th>C3</th>
            <th>C4</th>
            <th>C5</th>            
        </tr>
        </thead>
        <tbody>
        <tr template repeat="{{row in dataRows}}" >
            <td>{{row.s1}}</td>
            <td>{{row.s2)}}</td>
            <td>{{row.s3}}</td>
            <td>{{row.s4}}</td>
            <td>{{row.s5}}</td>
        </tr>
        </tbody>
    </table>
  </template>
  <script type="application/dart" src="clickcounter.dart"></script>
</polymer-element>

clickcounter.dart

import 'package:polymer/polymer.dart';

/**
 * A Polymer click counter element.
 */

class TableItem {
  String s1;
  String s2;
  String s3;
  String s4;
  String s5;

  TableItem(this.s1, this.s2, this.s3, this.s4, this.s5);
}

@CustomTag('click-counter')
class ClickCounter extends PolymerElement {


  @published var selIndex = 0;

  @observable List<TableItem> dataRows = [];

  ClickCounter.created() : super.created() {
    makeData(selIndex);
  }

  selIndexChanged(var oldVal, var newVal) {
    makeData(newVal);
  }

  void makeData(int newVal) {
    List newList = new List();
    for (int r = 0; r< 50; r++) {
      int i = newVal * r;
      String s = "${i}";
      newList.add(new TableItem("${i}-1", "${i}-2", "${i}-3", "${i}-4", "${i}-5"));

    }
    dataRows = toObservable(newList);
  }


}
1
Is it necessary to recreate the entire table (dataRows) every time instead of keeping it and just modifying values within TableItem or adding removing items from/to dataRows? You could try if it makes a difference when you change <td>{{row.s1}}</td> to <td>[[row.s1]]</td> (one time binding - I have no experience with it myself yet). - Günter Zöchbauer
Thanks for the tips (I was not aware of the one-time binding), both solve the problem. I'll post the comparision as an answer for future reference. - Lesiak
If you want the view be updated when you change values in TableItem then TableItem should add the Observable mixin and the fields have an @observable annotation (this doesn't help if you use one-time-binding of course). - Günter Zöchbauer

1 Answers

1
votes

Answering my question after Gunter's tips.

1 reassiging entire observable list

(as presented in question) - definitely the slowest

2 reassiging items in an observable list

improvement, but still unacceptable.

@observable List dataRows = toObservable([]);

void makeData(int newVal) {
  List newList = new List();
  for (int r = 0; r< 250; r++) {
    int i = newVal * r;
    String s = "${i}";
    newList.add(new TableItem("${i}-1", "${i}-2", "${i}-3", "${i}-4", "${i}-5"));
  }
  dataRows.clear();
  dataRows.addAll(newList);
}

3 reassiging items in an observable list with one time binding

much better, almost acceptable

Code changes as above, with one time binding:

<tr template repeat="{{row in dataRows}}" >
  <td>[[row.s1]]</td>
  <td>[[row.s2]]</td>
  <td>[[row.s3]]</td>
  <td>[[row.s4]]</td>
  <td>[[row.s5]]</td>
</tr>

4 No list reassingment, observable elements

Definitely the fastest, works fine even with 1000 rows :)

    class TableItemObs extends Object with Observable  {
      @observable String s1;
      @observable String s2;
      @observable String s3;
      @observable String s4;
      @observable String s5;

      TableItemObs(this.s1, this.s2, this.s3, this.s4, this.s5);
    }

    selIndexChanged(var oldVal, var newVal) {
      changeData(newVal);
    }

    void changeData(int newVal) {     
      for (int r = 0; r< 250; r++) {
        int i = newVal * r;
        dataRows[r].s1 = "${i}-1";
        dataRows[r].s2 = "${i}-2";
        dataRows[r].s3 = "${i}-3";
        dataRows[r].s4 = "${i}-4";
        dataRows[r].s5 = "${i}-5";                    
      }
    }

keep

<td>{{row.s1}}</td>

Update: I tested another option:

3a reassiging items in an observable list with one time binding, with batches

A variation of option 3, but adding after clearing the list new items are added in batches. Each function adds a part of the items.

Faster than option 3, but still below option 4.

selIndexChanged(var oldVal, var newVal) {            
    new Future(() => makeData1(newVal))
      .then((_) => makeData2(newVal))
      .then((_) => makeData3(newVal))
      .then((_) => makeData4(newVal))
      .then((_) => makeData5(newVal));                  
  }