Search code examples
dartdart-polymer

How to bind repeating nested templates to complex models


Eventually I want to bind templates to a tree model, but to understand how binding works beyond object properties (simple or chained), lists, and maps, I've created a two-level set of repeating templates bound to a corresponding Dart model. Each item in the outer list contains an inner list.

o1
  a
  b
o2
  c
  d

When I select an inner item (for example 'd'), the click handler highlights the item and appends an Inner object 'e' to the 'o2' Outer object's list. Inspecting the model in the debugger shows that 'e' has been added to the model, but it is not being added as an 'li' element to the HTML list. How do I revise my code so that the inner template detects the change?

HTML

<polymer-element name="nested-templates">
<template>
    <style>
        :host { display: block; height: 100%; }

        ul { margin: 0; padding: 0; }

        li { font-size: 0.85rem; padding-left: 0.75rem;  }
        li:hover { background: lightgrey; cursor: pointer; }
        li.selected { color: red; }
    </style>

    <div>
        <template repeat="{{o in outer}}">
            <strong>{{o.name}}</strong>
            <ul>
                <template repeat="{{i in o.inner}}">
                    <li id="{{i.name}}" on-click="{{innerClickHandler}}">{{i.name}}</li>
                </template>
            </ul>
        </template>
    </div>
</template>

<script type="application/dart" src="nested_templates.dart"></script>

Dart

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

@CustomTag('nested-templates')
class NestedTemplates extends PolymerElement {

    @observable List<Outer> outer = toObservable([
            new Outer('o1', [ new Inner('a'), new Inner('b')]),
            new Outer('o2', [ new Inner('c'), new Inner('d')])
    ], deep: true);

    void innerClickHandler(Event e, Map detail, HtmlElement target) {
        target.classes.add('selected');

        outer[1].inner.add(new Inner('e'));
    }

    NestedTemplates.created() : super.created();
}

class Inner extends Observable {
    String name;

    Inner(this.name);
}

class Outer extends Observable {
    String name;
    List<Inner> inner;

    Outer(this.name, this.inner);
}

pubspec.yaml

dependencies:
  ...
  polymer: 0.10.1+1
  polymer_expressions: 0.11.0
  ...
dependency_overrides:
  polymer_expressions: '0.11.0'

Solution

  • You need toObservable() for your inner too

    new Outer('o1', toObservable([ new Inner('a'), new Inner('b')])),