How do I extend <td> in Dart Polymer - dart

In Dart, I've been trying to create a polymer element that extends .
#CustomTag('deckname-td-item')
class DecknameTdItemElement extends TableCellElement with Polymer, Observable {
#published String item;
DecknameTdItemElement.created() : super.created();
void wordFileClicked(Event e, var detail, Node target) {
String deckName = $['deckAnchor'].text;
dispatchEvent(new CustomEvent('decknameclicked', detail: deckName));
}
}
Corresponding html:
<polymer-element name="deckname-td-item" extends="td">
<template>
<style>
a {
font-weight: bold;
}
</style>
<a id='deckAnchor' href="#" on-click="{{wordFileClicked}}">{{item}}</a>
</template>
<script type="application/dart" src="deckname_td_item.dart"></script>
</polymer-element>
Usage:
<td is="deckname-td-item" item="{{wordFile}}"
on-decknameclicked="{{deckNameChanged1}}"></td>
Everything works fine in Dartium, and it compiles without any warnings, but when I run the output of the build, I get:
Uncaught Unsupported operation: extendsTag does not match base native class
What am I doing wrong here?

HtmlDocument.register(String tag, Type customElementClass, {String extendsTag}) doc says
The [nativeTagName] parameter is needed by platforms without native support
when subclassing a native type other than:
HtmlElement
SvgElement
AnchorElement
AudioElement
ButtonElement
CanvasElement
DivElement
ImageElement
InputElement
LIElement
LabelElement
MenuElement
MeterElement
OListElement
OptionElement
OutputElement
ParagraphElement
PreElement
ProgressElement
SelectElement
SpanElement
UListElement
VideoElement
My guess is that polymer does provide this optional parameter

#CustomTag('ext-td')
class extendedTd extends TableCellElement with Polymer, Observable {
extendedTd.created() : super.created() {
polymerCreated();
}
}
I did this and mine worked properly.

Related

How to remove a nested dom rep element in dart using polymer >1.0

Hello I cant seem to find the correct way to remove a nested element using polymer 1.0
createMigrationTable.html
<dom-module id="custom-create-migration-table">
<template>
<style>
paper-button {
/**border: 1px solid #d81b60;*/
}
paper-material {
width: 98%;
margin: 5px auto;
}
br{
clear:both;
}
</style>
<paper-material elevation="2" id="page_2">
createTable:
<paper-button raised on-tap="addTable">
+ add new table
</paper-button>
<template is="dom-repeat" items="{{createTables}}">
{{item.name}}
<paper-input required label="Table Name" value="{{item.name}}"></paper-input>
<template is="dom-repeat" items="{{item.columns}}" as="column">
<custom-column-view column="{{column}}"></custom-column-view>
<a on-tap="removeColumn">remove</a>
<br/>
</template>
<paper-button raised on-tap="addColumn">
Add Column
</paper-button>
</template>
</paper-material>
</template>
</dom-module>
createMigrationTable.dart
#HtmlImport('createMigrationTable.html')
library dartabase.poly.createMigrationTable;
// Import the paper element from Polymer.
import 'package:polymer_elements/iron_pages.dart';
import 'package:polymer_elements/paper_material.dart';
import 'package:polymer_elements/paper_button.dart';
import 'package:polymer_elements/paper_input.dart';
//import "../poly/columnView.dart";
import "../poly/table.dart";
// Import the Polymer and Web Components scripts.
import 'package:polymer/polymer.dart';
import 'package:web_components/web_components.dart';
#PolymerRegister('custom-create-migration-table')
class CreateMigrationTable extends PolymerElement {
#property
List<Table> createTables = new List();
CreateMigrationTable.created() : super.created();
#reflectable
addTable(event, [_]) {
Table table = new Table(name:"defaultName",columns: [{
"name":"defaultName",
"type":["BINT",
"INT",
"VARCHAR"
],
"def":"",
"nil":true
}]);
/*Map table = {
"tableName":"defaultTableName",
"columns":[{
"name":"defaultName",
"type":"defaultType",
"default":"",
"notNull":true
}]
};*/
//createTables.add(table);
add('createTables', table);
}
#reflectable
transition(event, [_]) {
IronPages ip = Polymer.dom(this.root).querySelector("iron-pages");
ip.selectNext();
}
#reflectable
void addColumn(event, [_]) {
var model = new DomRepeatModel.fromEvent(event);
model.add("item.columns", {
"name":"defaultName",
"type":"",
"def":"",
"nil":true
});
}
#reflectable
void removeColumn(event, [_]) {
var model = new DomRepeatModel.fromEvent(event);
model.removeItem("item", model.item);
}
void ready() {
print("$runtimeType::ready()");
}
}
tabel.dart
import 'package:polymer/polymer.dart';
import 'package:web_components/web_components.dart';
class Table extends JsProxy {
#reflectable
String name;
#reflectable
List columns;
Table({this.name, this.columns});
}
what should be the correct way to remove the element.
first I tried to call remove from inside the custom-column-view. but that did not update the bindings
then I read that the parent elements should have the control over adding and removing elements.. so I moved it one level above.
I would have thought that I can do it like in the addColumn method but but inside removeColumn I only receive the column view item.
I also tried to use index-as but I dont know how to be able to access both indexes i and j inside the removeColumn functions.
A custom equals implementation might fix it (not sure)
class Table extends JsProxy {
#reflectable
final String name;
#reflectable
List columns;
Table({this.name, this.columns});
int get hasCode => name.hashCode;
int operator ==(Object other) => other is Table && other.name == name;
}

How to listen for event passed from parent to child in polymer.dart

I am trying to pass an event from a parent to child in Polymer 1.0.0-rc2 in Dart. The problem is that I do not know how to go about listening for the event in the child. I've tried to put the on-control-panel-refire attribute in the dom-module in the notation_view.html file, and calling handle button from there, but it didn't work. What is the proper way to listen for this event? I know that on-control-panel-button-pressed is working well.
notation_view.dart
#PolymerRegister('notation-view')
class NotationView extends PolymerElement {
NotationView.created() : super.created();
#reflectable
handleButton(Event e, var detail) {
print("received");
}
}
main_app.dart
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
MainApp.created() : super.created();
#reflectable
refire(Event e, var detail) {
querySelector('notation-view').dispatchEvent(new CustomEvent("control-panel-refire",
detail: {'name' : detail["button-id"]}));
}
main_app.html
<link rel="import" href="notation_view.html">
<dom-module id="main-app">
<style>
:host {
display: block;
}
</style>
<template>
<notation-view id="notation-view"></notation-view>
<control-panel id="control-panel" on-control-panel-button-pressed="refire"></control-panel>
</template>
</dom-module>
notation_view.html
<dom-module id="notation-view" >
<style>
:host {
display: block;
}
</style>
<template>
<canvas id="canvas" width="1000" height="1000"></canvas>
</template>
</dom-module>
I haven't actually tried this but I think instead of
querySelector('notation-view').dispatchEvent(new CustomEvent("control-panel-refire",
detail: {'name' : detail["button-id"]}));
}
it should be
new PolymerDom(root).querySelector('notation-view').fire("control-panel-refire",
detail: {'name' : detail["button-id"]}));
}
You can cast the result of querySelector() to PolymerElement or NotationView if the analyzer complains about the unknown fire() method.
To listen to an event use
#PolymerRegister('notation-view')
class NotationView extends PolymerElement {
NotationView.created() : super.created();
#reflectable
handleButton(Event e, var detail) {
print("received");
}
#Listen('control-panel-refire')
void handleControlPanelRefire(CustomEvent e, [_] /* or `Map detail` instead of [_] */) {
// handle event
}
// alternatively
EventSubscription _controlPanelRefireSubscr;
attached() {
super.attached();
_controlPanelRefireSubscr = this.on['control-panel-refire'].listen((event) {
// handle event
});
}
detached() {
super.detached();
_controlPanelRefireSubscr?.cancel();
}
}

Polymer Dart, global variables and data bindings (observable)

I read Polymer API developer guide, but unfortunately it has examples only for JavaScript developers. Some examples I try to port into Dart, but in this case I get fail. Please, go to https://www.polymer-project.org/0.5/docs/polymer/polymer.html#global (Section Supporting global variables). Here is a clip from the documentation:
elements.html
<polymer-element name="app-globals">
<script>
(function() {
var values = {};
Polymer({
ready: function() {
this.values = values;
for (var i = 0; i < this.attributes.length; ++i) {
var attr = this.attributes[i];
values[attr.nodeName] = attr.value;
}
}
});
})();
</script>
</polymer-element>
<polymer-element name="my-component">
<template>
<app-globals id="globals"></app-globals>
<div id="firstname">{{$.globals.values.firstName}}</div>
<div id="lastname">{{$.globals.values.lastName}}</div>
</template>
<script>
Polymer({
ready: function() {
console.log('Last name: ' + this.$.globals.values.lastName);
}
});
</script>
</polymer-element>
index.html
<app-globals id="globals" firstname="Addy" lastname="Osmani"></app-globals>
Questions:
How to implement this code in Dart?
Reading the code of different Q&A concerning Dart Polymer usage I come across with #observable annotation, toObserve() function and class CustomElement extends PolymerElement with Observable {..}. I know that they somehow related with data bindings, but I have no idea exactly how.
app_gobals.html
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="app-globals">
<template>
<style>
:host {
display: none;
}
</style>
</template>
<script type="application/dart" src="app_globals.dart"></script>
</polymer-element>
app_gobals.dart
import 'package:polymer/polymer.dart';
import 'dart:async' show Timer;
#CustomTag('app-globals')
class AppGlobals extends PolymerElement {
static final ObservableMap _staticValues = toObservable({});
Map get values => _staticValues;
AppGlobals.created() : super.created();
ready() {
attributes.keys.forEach((k) {
values[k] = attributes[k];
});
// just to demonstrate that value changes are reflected
// in the view
new Timer.periodic(new Duration(seconds: 2),
(_) => values['periodic'] = new DateTime.now());
}
}
app_element.html (your my-component)
<link rel="import" href="packages/polymer/polymer.html">
<link rel="import" href="app_globals.html">
<polymer-element name="app-element">
<template>
<style>
:host {
display: block;
}
</style>
<app-globals id="globals"></app-globals>
<div>{{$["globals"].values["firstname"]}}</div>
<div>{{$["globals"].values["lastname"]}}</div>
<div>{{$["globals"].values["periodic"]}}</div>
</template>
<script type="application/dart" src="app_element.dart"></script>
</polymer-element>
app_element.dart
import 'package:polymer/polymer.dart';
#CustomTag('app-element')
class AppElement extends PolymerElement {
AppElement.created() : super.created();
ready() {
print('Last name: ${$["globals"].values["lastName"]}');
}
}
#observable indicates that Polymer should be notified when the value changes so it can update the view.
If you have a collection this is not enough because Polymer only gets notified when the field changes (another collection or null is assigned). toObservable(list|map) ensures that Polymer gets notified when elements in the collection are changed (removed/added/replaced).
PolymerElement includes Observable there fore there is nothing special to do on class level. When you extend a DOM element this looks a bit different see https://stackoverflow.com/a/20383102/217408.
Update
This are a lot of questions. I use static final ObservableMap _staticValues = toObservable({}); to ensure all values are stored in one place no matter how many <app-globals> elements your application contains. Statics are stored in the class not in the instance therefore it doesn't matter how many instances exist. #ComputedProperty(expression) var someField; watches expression for value changes and notifies Polymer to update bindings to someField. #observable is the simpler version but works only for fields. #published is like #observable but in addition allows bindings to the field from outside the element. #PublishedProperty() is the same as #published but this annotation form allows to pass arguments. #PublishedProperty(reflect: true) is like #published but in addition updates the actual DOM attribute to make the bound value available not only for other Polymer elements to bind to but also for CSS or other Frameworks which have no knowledge how to bind to Polymer fields.
I found another solution that works for me:
Just define a class for your globals. Use a factory constructor so that every representation of the class is the same instance. The class must extend Object with Observable:
globals.dart:
library globals;
import 'package:polymer/polymer.dart';
class Globals extends Object with Observable {
static Globals oneAndOnlyInstance;
#observable String text; // a "global" variable
#observable int integer; // another "global" variable
factory Globals() {
if (oneAndOnlyInstance==null) {
oneAndOnlyInstance=new Globals.init();
}
return oneAndOnlyInstance;
}
Globals.init();
}
Now you can use this class inside of all your custom elements. Only need to import globals.dart and create an object of it:
inside: main_app.dart:
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'package:abundan/classes/globals.dart';
/// A Polymer `<main-app>` element.
#CustomTag('main-app')
class MainApp extends PolymerElement {
Globals globals=new Globals();
/// Constructor used to create instance of MainApp.
MainApp.created() : super.created();
attached() {
super.attached();
globals.text="HELLO!";
}
and inside of main_app.html:
{{globals.text}}
This works for me and it seems to be the easiest way to have something like globals with polymer custom elements.

Dart Polymer #observable variable initialization handling in polymer 0.10.0

I have run across a strange behaviour after upgrading from polymer 0.9.5 to 0.10.0+1.
I have 2 elements, parent and child.
Parent defines a #observable variable.
If I initialize this variable at declaration site and in created(), the app never launches.
Is that expected?
#CustomTag('parent-elem')
class ParentElem extends PolymerElement {
//#observable String myValue1 = "Init value"; //Fails
#observable String myValue1; //works fine
ParentElem.created() : super.created() {
myValue1 = "Hello world";
}
}
This is used by a child Element:
#CustomTag('second-elem')
class ClickCounter extends PolymerElement {
#published String myValue2;
ClickCounter.created() : super.created() {
}
}
And bound via:
<link rel="import" href="secondelem.html">
<polymer-element name="parent-elem">
<template>
<div>
<h1>Parent elem</h1>
<span>(my value: {{myValue1}})</span>
</div>
<second-elem myValue2="{{myValue1}}"></second-elem>
</template>
<script type="application/dart" src="parent_elem.dart"></script>
</polymer-element>

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:
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'!!!
});`
}
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
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();
}
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

Resources