Search code examples
dartdart-polymer

Maps in Lists in Maps


After much trial and error, I am at a loss as to how to deal with embedded lists and maps in Dart and furthermore, how they can be accessed via Polymer data binding. The objective is to read a JSON file and build an HTML table that can be filtered and sorted. (I just hard coded map data below for clarity.)

I can build an HTML table within my Polymer element (see buildTable) as long as the Map looks like testMap3 seen in the Dart code below and it renders fine with:

HTML:

<p><b>The data from testMap3 after building table in Dart file:</b>/p> 
<table class="bordered" id="dataTable"></table>     

However, I can't seem to figure out how to do this via Polymer data binding. Right now I am just dumping the k-v pairs, just so that I can see the objects:

HTML:

<p><b>The data from testMap3 via Polymer binding:</b></p> 
<template repeat="{{key in testMap.keys}}">
  <p>{{key}} : {{testMap[key]}}</p>   
</template>

How can I use data binding to create a table that would match the result of the first example above? And to make things more difficult, how can I do so using testMap2 instead?

Dart:

Rendering testMap3 works fine when calling buildTable:

Map testMap3 = toObservable({
                'columns' : ["First Name", "Attending", "Phone"],
                'rows' : [{'First Name' : "Alice", 
                           'Attending' : "Yes",
                           'Phone' : "555-1212"},                              
                          {'First Name' : "Bob", 
                           'Attending' : "Yes",
                           'Phone' : "555-2323"}                              
                         ]
           });

Iterating through testMap2 has been problematic given the additional embedded 'Phone' value is a list containing another map:

 Map testMap2 = toObservable({
               'columns' : ["First Name", "Attending", "Phone"],
               'rows' : [{'First Name' : "Alice", 
                          'Attending' : "Yes",
                          'Phone' : [{'Home' : "555-1234",
                                      'Work' : "555-4321",
                                      'Mobile' : "555-1212"}]},                              
                         {'First Name' : "Bob", 
                          'Attending' : "Yes",
                          'Phone' : [{'Home' : "555-2345",
                                      'Work' : "555-5432",
                                      'Mobile' : "555-2323"}]}                            
                        ]
          });

The following code works fine for testMap3 but nothing I have tried lets me loop through the phone data if I use testMap2. Any ideas on how I can do this?

buildTable() {

  TableElement table = this.shadowRoot.querySelector("#dataTable");
  table.children.clear();

  TableSectionElement tBody = table.createTBody();

  TableSectionElement tHead = table.createTHead();
  TableRowElement trh = tHead.addRow();

  for (var column in testMap3["columns"]) {
    var cell = new Element.tag('th');
    cell.text = column;
    trh.append(cell);
  }

  for (var row in testMap3["rows"]) {

    TableRowElement tr = tBody.addRow();
    for (var column in testMap3["columns"]) {
      tr.addCell().text = row[column];       
    }
  }   
}

Finally, one of the ultimate goals is to filter all the columns in the rendered table taking an approach similar to the following...is this doable? I can't seem to find examples using Maps or even Lists within Lists.

HTML:

<template repeat="{{city in listOfCities | filter(searchParameter)}}">
  <li>{{city}}</li>
</template>

Dart:

@observable List listOfCities = ["Chicago", "New York", "Los Angeles", "Dallas", "Denver"];

filter(term) => (listOfCities) => term.isEmpty ? listOfCities : listOfCities.where((item) => item.toLowerCase().contains(searchParameter.toLowerCase())).toList();

Any guidance is greatly appreciated as I have been banging my head for over a week and am just about ready to give up.

Thanks!


Solution

  • The following Polymer databinding will work for testMap3:

    <table>
      <thead>
        <tr>
          <td template repeat="{{column in testMap3['columns']}}">{{column}}</td>
        </tr>
      </thead>
      <tbody>
        <tr template repeat="{{row in testMap3['rows']}}">
          <td template repeat="{{data in row.keys}}">{{row[data]}}</td>
        </tr>
      </tbody>
    </table>
    

    Filtering on table rows could be accomplished with the following method:

    filter(term) => (rows) => term.isEmpty
          ? rows
          : rows.where((row) => row.values.any((val) => val.toLowerCase().contains(term)));
    

    It looks through the entire row data and matches each column against the search term.

    The tbody would then look like this:

    <tbody>
      <tr template repeat="{{row in testMap3['rows'] | filter(search)}}">
        <td template repeat="{{data in row.keys}}">{{row[data]}}</td>
      </tr>
    </tbody>
    

    And it assumes you have a text input that hooks up to a String value named search.