Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dart-polymer: cannot set an attribute from an event handler

The following code doesn't work. Maybe I do something wrong.. Please correct my code:

  1. index.html:
<html>
<head>
    <title>Page</title>
    <link rel="import" href="msg_box.html">
</head>
<body>
  <msg-box id="msg" caption="Caption 1"></msg-box>
  <button id="btn">click me</button>
<script type="application/dart" src="index.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'msg_box.dart';

void main() {
  initPolymer();

  ButtonElement btn = querySelector("#btn");

  btn.onMouseEnter.listen((e) {
    MsgBoxElement elm = querySelector("#msg");

    window.alert(elm.caption); // SHOWS 'Caption 1'

    elm.caption = "Caption 2"; // DON'T WORK!

    window.alert(elm.caption); // SHOWS 'Caption 2', BUT PAGE SHOWS 'Caption 1'!!!
  });`
}
  1. msg_box.html
<polymer-element name="msg-box" attributes="caption">
  <template>
  <h4>{{caption}}</h4> 
  </template>
  <script type="application/dart" src="msg_box.dart"></script>
</polymer-element>
import 'package:polymer/polymer.dart';
@CustomTag('msg-box')
class MsgBoxElement extends PolymerElement {
  // fields
  String _caption;
  String get caption => _caption;
  void set caption(String value) {
    _caption = notifyPropertyChange(#caption, _caption, value);
  }

  MsgBoxElement.created() : super.created() {
  }
}

This issue is critical for me. See also https://code.google.com/p/dart/issues/detail?id=14753&sort=-id&colspec=ID%20Type%20Status%20Priority%20Area%20Milestone%20Owner%20Summary

like image 692
Roman Avatar asked Nov 04 '13 10:11

Roman


2 Answers

I believe the problem here is that there are pending change notifications not being processed because your code is not running in the dirty-checking zone. There are two things you can do to fix this:

  • call Observable.dirtyCheck() right after your update to caption; or,
  • run your code within the dirty-checking zone:
void main() {
  var dirtyCheckingZone = initPolymer();
  dirtyCheckingZone.run(() {
     ButtonElement btn = querySelector("#btn");
     btn.onMouseEnter.listen((e) {
       MsgBoxElement elm = querySelector("#msg");
       elm.caption = "Caption 2";
    });
  });
}

This zone makes sure that after any callback or listener is executed, we'll call Observable.dirtyCheck for you. This approach is slightly better than calling dirtyCheck explicitly because, when we compile for deployment, we switch from dirty-checking to explicit notifications. The zone returned by initPolymer is changed to reflect this.

A separate note: the MsgBoxElement above can be simplified if you use the @published annotation. This is meant to express that a property is both observable and exposed as an attribute of your element.

import 'package:polymer/polymer.dart';

@CustomTag('msg-box')
class MsgBoxElement extends PolymerElement {
  @published String caption;
  MsgBoxElement.created() : super.created();
}
like image 116
Siggi Cherem Avatar answered Sep 30 '22 15:09

Siggi Cherem


Based on your information, it appears that the model is being updated, however the DOM isn't updating, most likely because an observable element isn't set. Try adding the following annotations to your msg_box dart code:

import 'package:polymer/polymer.dart';
@CustomTag('msg-box')
class MsgBoxElement extends PolymerElement {
  // fields
  @observable String _caption;
  @reflectable String get caption => _caption;
  @reflectable void set caption(String value) {
    _caption = notifyPropertyChange(#caption, _caption, value);
  }

  MsgBoxElement.created() : super.created() {
  }
}

See this Breaking change announcement on the dart mailing lists regarding the @reflectable attribute. Also see this discussion on setting up @observable getters

like image 43
Matt B Avatar answered Sep 30 '22 13:09

Matt B