timecc
timecc

Reputation: 161

Dart data binding from a parent custom element to attributes of a child custom element

Here is a problem that cropped up today when I updated to the latest Dart libs.

The child custom element is a combo box. The parent custom element fills it with a varying list of strings.

// child HTML
<polymer-element name="bx-icombo" attributes="aLabel aList aSelected">
  <template>
    <div class='outr' flex layout horizontal center>
      <label for='inp' flex end-justified>{{aLabel}}</label>
      <!-- wait until the data is available -->
      <template if='{{aList}}'>
        <paper-dropdown-menu id='inp' label='aLabel' valign='top' flex start-justified >
          <paper-dropdown class="dropdown">
            <core-menu id='m' class="menu" selected="{{aSelected}}">
              <template repeat='{{aList}}'>
                <paper-item name='{{}}'>{{}}</paper-item>
              </template>
            </core-menu>
          </paper-dropdown>
        </paper-dropdown-menu>
      </template>
    </div>
  </template>

  <script type='application/dart' src='bx_icombo.dart'></script>
</polymer-element>

//---------------------------------------------------------------
// child Dart
@CustomTag('bx-icombo')
class BxICombo extends PolymerElement {

  @PublishedProperty(reflect: true)  String       aLabel;
  @PublishedProperty(reflect: true)  List<String> aList;
  @PublishedProperty(reflect: true)  String       aSelected;

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

//---------------------------------------------------------------
// Parent HTML
<polymer-element name="tst-sigs">
  <template>
    <paper-dialog backdrop heading='Sigs' closeSelector=''>
      <bx-icombo aLabel='{{selectAsignal}}'
                 aList='{{sigsList}}'
                 aSelected='{{sigsSel}}'>
      </bx-icombo>
    </paper-dialog>
  </template>

  <script type='application/dart' src='tst_sigs.dart'></script>
</polymer-element>

//---------------------------------------------------------------
// Parent Dart
@CustomTag('tst-sigs')
class TstSigs extends PolymerElement {

  @observable List<String> sigsList = ['alpha', 'beta', 'gamma'];
  @observable String sigsSel;
  @observable String selectAsignal = 'Select a Signal';

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

//---------------------------------------------------------------

Dartium reports:

Attributes on bx-icombo were data bound prior to Polymer upgrading the element. This may result in incorrect binding types. (:1)

So what has to be changed? @PublishedProperty or @observable or @published or .... I admit to finding the maze of @... annotations deeply unclear.

The versions are:

Dart: 1.9.3 (STABLE)
Dartium: 39.0.2171.99

and packages:

analyzer 0.24.6 (0.25.0+1 available)
args 0.12.2+6 (0.13.0 available)
barback 0.15.2+4
browser 0.10.0+2
cli_util 0.0.1+1
code_transformers 0.2.8
collection 1.1.0
core_elements 0.7.1+2
csslib 0.12.0
dart_style 0.1.8
glob 1.0.4
html 0.12.1+1
ini 1.1.0
initialize 0.6.0+4
intl 0.12.2
js 0.3.0
logging 0.9.3 (0.10.0 available)
markdown 0.7.1+2
matcher 0.11.4+4 (0.12.0-alpha.0 available)
observe 0.13.0+2
paper_elements 0.7.1
path 1.3.5
petitparser 1.3.7
polymer 0.16.1+4
polymer_expressions 0.13.1
polymer_interop 0.1.0+2
pool 1.0.1
quiver 0.21.3
smoke 0.3.2
source_maps 0.10.0+2
source_span 1.1.2
stack_trace 1.3.1
string_scanner 0.1.3+1
template_binding 0.14.0+2
utf 0.9.0+2
watcher 0.9.5
web_components 0.11.2
when 0.2.0
which 0.1.3
yaml 2.1.2

Initially a problem with code-transformers forced code_transformers < 0.2.5 and that limited polymer to 0.16.0. It looks as if the code transformer thing has been resolved so I have removed the version constraint and polymer updated to 0.16.1. The problem remains.

The main function is

import  'package:polymer/polymer.dart';
import  'lib/bxglobs/bxGlobs.dart' as G;

void realMain() {
  // empty for this test
}

void main() {

  G.initGlobals();

  initPolymer().then((zone) => zone.run(() {
    Polymer.onReady.then((_) => realMain());
  }));
}

and pubspec.yaml:

name: bxPoly
description: BX GUI
dependencies:
  core_elements: any
  ini: any
  intl: any
  js: any
  markdown: any
  paper_elements: any
  polymer: any
  code_transformers: any
transformers:
- polymer:
    entry_points:
    - web/test.html

Upvotes: 2

Views: 378

Answers (3)

timecc
timecc

Reputation: 161

This seems to be the solution. Based on debugging rather than knowledge, so beware..

Say your component foo.dart and foo.html refers to another component bar.dart and bar.html. For instance, the reference might be:

barEl el = document.querySelector('bar');

Obviously you import bar.dart at the top of foo.dart. You get the error described unless you also

<link rel="import" href="bar.html">

at the top of foo.html. Even though bar.html is not conventionally referenced in foo.html.

Upvotes: 0

Jake MacDonald
Jake MacDonald

Reputation: 1348

This error almost always occurs because of elements getting registered in the wrong order. Specifically, a parent element being registered before a child element.

This is hard to diagnose without full access to the code, but following these two rules should ensure its not an issue:

  • Put each polymer-element in its own html file, and each class in its own dart library (using parts especially causes issues).
  • Make sure your elements import all of their dependencies.

Upvotes: 1

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 658037

edit

  <template if='{{aList != null}}'>
    <paper-dropdown-menu id='inp' label='aLabel' valign='top' flex start-justified >
      <paper-dropdown class="dropdown">
        <core-menu id='m' class="menu" selected="{{aSelected}}">
          <template repeat='{{a in aList}}'>
            <paper-item name='{{a}}'>{{a}}</paper-item>
          </template>
        </core-menu>
      </paper-dropdown>
    </paper-dropdown-menu>

original

  • If you bind from the shadow DOM of an element to its class @observable is enough.
  • If you want to bind to attributes from outside of an element use @published.
  • If you want to use the value of a bound attribute for example in CSS selectors use @PublishedAttribute(reflect: true). reflect means the properties value is reflected to the DOM, otherwise it's only available for Polymer and Dart code.

I haven't seen this error message before. Maybe there is a problem with Polymer initialization. Do you have a custom main? Can you add it to your question?

class MyA extends PolymerElement {
  @observable 
  aobservable = 'obs';

  @published 
  apublished = 'pub';

  @PublishedAttribute(reflect: true)
  areflected = 'ref';
}
<polymer-element name="my-a">
  <template>
    <!-- doesn't work
    <my-b bobservable="{{aobservable}}"></my-b> -->

    <my-b bpublished="{{aobservable}}"></my-b>
    <my-b breflected="{{aobservable}}"></my-b>
    <!-- you can bind properties of MyA here no matter if 
         they are observable/published/reflected
         (even when they have no annotation but they will not
         be updated when the value changes) 

         You can bind only to published (reflected or not)
         attributes of MyB
    -->
  </template>
</polymer-element>

class MyB extends PolymerElement {
  @observable 
  bobservable = 'obs';

  @published 
  bpublished = 'pub';

  @PublishedAttribute(reflect: true)
  breflected = 'rep';
}
<polymer-element name="my-b">
  <template>
  </template>
</polymer-element>
<head>
  <style>
    // you can only address reflected attributes here
    my-a[areflected="ref"] {
      backgroundColor: red;
    }
  </style>
</head>
<body>
 <my-a></my-a>
</body>

Upvotes: 0

Related Questions