Friday, December 13, 2013

Wait a Second, I Know This…


Sometimes there is no substitute for a small test case. I begrudge every minute that I have to work on small test cases instead of the actual task at had, but often there is nothing for it but to break down and write that small test case. Unless someone does it for you that is.

That someone in this case is James Hurford. Having witnessed my meltdown in yesterday's post on Polymer.dart, he (like me) thought, “that should work.” And so, he wrote a small test case that proved it worked. Having no luck in my own code, I switched to his and gave it whirl.

And it still did not work.

So clearly James is wrong and I'm right… right? Long time readers of this blog already know the answer is that I'm wrong. To prove myself wrong, I converted James' test case into simpler named <x-parent> and <x-child> tags. The parent needs to communicate to the child. In the parent template, I bind the <x-parent>'s observable count variable with the <x-child>'s attribute of the same name:
<link rel="import" href="child.html">
<polymer-element name="x-parent">
  <template>
    <div>
      <h2>Parent</h2>
      <span>(item count: {{count}})</span>
      <x-child count="{{count}}"></x-child>
    </div>
  </template>
  <script type="application/dart" src="parent.dart"></script>
</polymer-element>
With that, whenever the observable count instance variable in <x-parent> changes, the attribute/instance variable in <x-child> should change as well.

Adapting James' code, my <x-child> backing class is where I make changes to the doubly bound variable:
import 'package:polymer/polymer.dart';
import 'dart:async';

@CustomTag('x-child')
class Child extends PolymerElement {
  @published int count = 0;

  Child.created() : super.created();

  @override
  void enteredView() {
    super.enteredView();
    new Timer.periodic(
      new Duration(milliseconds: 900),
      (t){
        count++;
        print(count.toString());
      }
    );
  }
}
Every 900 milliseconds, the count is incremented and should be reflected in both parent and child element. Except it is not:



Just as I saw yesterday, the actual value is be changed, as evidenced by the console output on the right. And just as yesterday, the actual bound variables are not being updated.

So I try this with just the <x-child> element and no bound variables thinking that perhaps there is a bug in data binding. And it still does not work.

It is at this point that something from deep within the recessed of my brain stirs. This is bound variables not updating. I know this. In fact, I submitted the damn bug not 7 days ago. Happily, I included a workaround in that bug. After following my own advice, and downgrading the observable package in my pubspec.yaml:
name: parent_child
dependencies:
  polymer: any
  observe: "0.9.0+1"
dev_dependencies:
  unittest: any
After a pub upgrade (downgrade?), it works:



I cannot believe that I have now run into the same extremely annoying problem twice and failed to recognize it the second time. And yes, downgrading the observe package in last night's code (and removing a ton of debug code) fixed the problem.

My own shame aside, I have successfully identified the Polymer way of communicating between parent and child. As long as a buggy version of Dart's observe package is not used, this data binding approach works just as well in Dart as it did previously in the JavaScript version of the code. And I would not have been able to prove this without James' help. So thanks James!


Day #964

7 comments:

  1. That's funny, as the version of observable I'm using is 0.9.2. The bug must been fixed in this version? Obviously the workaround you did, worked though. Were you using an earlier or later version to the one I am using?

    ReplyDelete
  2. I'm also using Dart SDK version 1.0.3.0_r30939

    ReplyDelete
  3. I actually tried putting that constraint on observe "0.9.0+1", but it refused to do it with the following message

    Incompatible version constraints on 'observe':
    - 'observe' depends on version >=0.9.0 <0.10.0

    So I'm guessing it has to do with the combination of the Dart version you're using and the latest observe library. Of coarse that message isn't that helpful without knowing the context, so my guess might be wrong.

    ReplyDelete
    Replies
    1. I see the same constraint error when I try 1.0.3.0_r30939 and 0.9.0.

      Interestingly, I do not see this working with observe 0.9.2 (or 0.9.3) in that version or 1.0.0.10_r30798 . Currently the most recent version of the SDK and library in which bound variables are updating for me is 1.0.0.10_r30798 and 0.9.0+1.

      I guess at least it's working, but it seems very strange that more recent stuff works for you but not me. Maybe it's OS specific? I'm on linux. I'm also not compiling to JS, just running in Dartium.

      Weirdness.

      Delete
    2. I'm also using the DartEditor, and keeping this up to date. Sorry should have mentioned that.

      Yeah that is weirdness. I'm also running Linux, in fact it's an out of date Gentoo distribution, by about a month.

      I'm also running this in Dartium. Maybe it's the version of Dartium you're using?

      Delete
    3. I'm using whichever version of Dartium comes bundled with the current version of Dart. Currently I have Version 31.0.1650.39 (1593), which comes with Dart 1.0.0.10_r30798.

      Every time I switch versions I:

      * Close Dartium
      * Stop pub serve
      * Move the old Dart to a backup location
      * Unzip the new Dart
      * Pub upgrade dependecies
      * Start pub serve
      * Start Dartium

      I do wonder if I'm missing something because this bug prevents the basic button click-counter example from working (as reported in https://code.google.com/p/dart/issues/detail?id=15512). I would think others would be going crazy if this weren't isolated to me.

      Then again, why can I reliably fix the problem by downgrading to observe 0.9.0? Prolly worth a deep dive at some point, but this weekend I need to get the alpha release of the book together. Maybe early next week...

      Delete
  4. Well I was reaching there for a reason. I do that a lot, but I can see the mystery will have to wait till later to be solved. I wish I could replicate your problem and have a look at it myself, but I can't easily. I'll leave you get onto the next stage.

    ReplyDelete