Dart polymer datatable widget

I have created a polymer widget that draws a datatable from a data source url. The code is at https://github.com/dennisfrancis/polymer-dart-datatable-example

Here is the template of the polymer widget

<polymer-element name="dennis-datatable" attributes="dataSrc,jsonArgs,refreshInterval,method">
 
  <template>
  <link rel="stylesheet" href="dennis_datatable.css">

    <div>
      <button id="refresh_button" on-click="{{fetch_data}}">Refresh</button>
      <table class="bordered" id="datatable_table">
        <tr>
          <th template repeat="{{col in cols}}">
              {{col}}  
          </th>
        </tr>
        <tr template repeat="{{row in rows}}">

            <td template repeat="{{col in cols}}">
              {{row[col]}}  
            </td>
        </tr>
      </table>
    </div>
  </template>
  <script type="application/dart" src="dennis_datatable.dart"></script>
</polymer-element>

And here is the dart code of the widget that also prints the rendering latency to the Dartium console.

import 'package:polymer/polymer.dart';
import 'dart:async';
import 'dart:html';
import 'dart:convert';

/**
 * A Polymer datatable element.
 */
@CustomTag('dennis-datatable')
class DataTable extends PolymerElement {
  @published String dataSrc;
  @published String jsonArgs = "{}";  // Sorting can be done on server side by passing something like sortcol:"colname"
  @published int refreshInterval = 0;
  @published String method = "GET";
  
  @observable int numrows = 0;
  @observable int numcols = 0;
  @observable List<String> cols;
  @observable List<Map<String,dynamic>> rows;
  
  ButtonElement refreshButton;
  bool doing_refresh = false;
  
  Timer fetch_timer;
  
  String _json_response = "";
  
  MutationObserver observer;
  
  DateTime _start_render;
  DateTime _stop_render;

 
  DataTable.created() : super.created() {
    
    observer = new MutationObserver(_onMutation);
    observer.observe(getShadowRoot('dennis-datatable').querySelector('#datatable_table'), childList: true, subtree: true);

    refreshButton = this.shadowRoot.querySelector("#refresh_button");
    
    fetch_data();
    
    if (refreshInterval != 0) {
      fetch_timer = new Timer.periodic(new Duration(seconds : refreshInterval), fetch_data);
    }
  }
  
  void _onMutation(List<MutationRecord> mutations, MutationObserver observer) {
    print('${mutations.length} mutations occurred, the first to ${mutations[0].target}');
    _prn_stat();
  }
  
  void fetch_data([Timer _]) {

    if (doing_refresh) { return; }
    
    refreshButton.disabled = true;
    
    doing_refresh = true;

 
    if (dataSrc.isEmpty) { return; }

    HttpRequest request = new HttpRequest(); // create a new XHR
    
    // add an event handler that is called when the request finishes
    request.onReadyStateChange.listen((_) {
      if (request.readyState == HttpRequest.DONE &&
          (request.status == 200 || request.status == 0)) {
        // data saved OK.
        //print(request.responseText); // output the response from the server
        if (_json_response != request.responseText) {  // Avoid json parsing and rendering if same data
          update_data(request.responseText);
          _json_response = request.responseText;
        } else {
          print("No new data");
        }
        
      }
      doing_refresh = false;
      refreshButton.disabled = false;
    });

    // POST the data to the server
    request.open(method, dataSrc);

    if(method == "POST") {
      request.send(jsonArgs); // perform the async POST
    } else {
      request.send();
    }
    
  }
    
  void update_data(String jsonString) {
    
    Map data = JSON.decode(jsonString);
    
    numrows = data["numrows"];
    numcols = data["numcols"];
    cols    = data["cols"];
    rows    = data["rows"];
    
    _start_render = new DateTime.now();
    
  }
  
  void _prn_stat() {

    if (_start_render == null) { return; }
    
    _stop_render = new DateTime.now();
    int diff = _stop_render.millisecondsSinceEpoch - _start_render.millisecondsSinceEpoch;
    
    print("render time = $diff ms");
    
  }
  
}

The sad part about this widget is that the rendering time is about 20 times worse than what it would take a raw dart program to generate a table with the same data.
See my previous post about rendering latency without using polymer widgets.

I decided to move the table rendering logic from templates to a dart function, until polymer template rendering speed improves. I created a new git branch called min_templates for the same project at github.

Now the rendering latency is competitive to that of the non-polymer dart table benchmark

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s