Nested Polymer Custom Components Data Binding - dart

I cannot get data to round trip from a child component to the parent component and back to a child component.
I have made a simple nested component testbed. Here is the child:
<link rel="import" href="../packages/polymer/polymer.html">
<polymer-element name="child-comp" attributes="x y">
<template>
<input type='text' value='{{x}}'/>
<p>-x={{x}}-</p>
<p>list:
<template repeat='{{y}}'>-{{ }}-</template>
</p>
</template>
<script type='application/dart'>
import 'package:polymer/polymer.dart';
#CustomTag('child-comp')
class ChildComp extends PolymerElement {
#observable var x;
#observable var y;
ChildComp.created() : super.created();
}
</script>
</polymer-element>
It takes a text input (x) and echoes it out (the p immediately after the input). It also send x back to the parent control where it is added to a list (y) that should then be iterated through in the child.
Here is the parent component:
<link rel="import" href="../packages/polymer/polymer.html">
<link rel="import" href="../components/child_comp.html">
<polymer-element name="top-comp">
<template>
<child-comp x='{{s}}' y='{{t}}'></child-comp>
</template>
<script type='application/dart'>
import 'package:polymer/polymer.dart';
#CustomTag('top-comp')
class TopComp extends PolymerElement {
#observable String s = '1234';
#observable List<String> t = ['A', 'B', 'C'];
TopComp.created() : super.created();
sChanged(oldVal, newVal) {
t.add(newVal);
}
}
</script>
</polymer-element>
From the child to the parent works and the change is correctly added to the List. But the List does not seem to get to the child - the DOM is never updated.
I have tried every possible combination of the decorators, but perhaps the answer is in a variant of the bind= syntax..
A side note: is there authoritative updated documentation on the decorators? Searching turns up a bunch of references of varying antiquity.

If I understand your problem correctly, you need to make sure that not only is your List observable, but also its elements. You can do so like this:
#observable List<String> t = toObservable(['A', 'B', 'C']);
This way, changes to t's elements (instead of just t itself) are "announced", and the DOM can update accordingly.

Related

Can't create a Polymer Core Element in dart

I basically want to create a <core-tooltip> tag, not in HTML, but in dart.
So i tried:
CoreTooltip tooltip = new CoreTooltip();
CoreTooltip tooltip = document.createElement("core-tooltip"):
CoreTooltip tooltip = new Element.tag("core-tooltip"):
got always the same Exception
Uncaught Error: type 'HtmlElement' is not a subtype of type 'CoreTooltip'
Why does that just not work?
You shouldn't use this method
document.createElement("core-tooltip"):
the other two are fine though.
I assume the element creation fails because the code is in a custom main and is executed before Polymer is done with initialization.
See how to implement a main function in polymer apps for more details.
If you execute the code inside a Polymer elements (for example attached() method after super.attached()) or in an event handler like on-click this will work.
Another possibility is, that you app is missing an HTML import that imports <core-tooltip>. Without an import this can't work either.
I tried it with this code and it worked for me
app_element.dart
import 'dart:html' as dom;
import 'package:polymer/polymer.dart';
import 'package:core_elements/core_tooltip.dart';
#CustomTag('app-element')
class AppElement extends PolymerElement {
AppElement.created() : super.created() { }
#PublishedProperty(reflect: true) bool isValidationError;
void attached() {
super.attached();
CoreTooltip tt = new CoreTooltip();
print(tt);
}
}
app_element.html
<link rel="import" href="../../packages/polymer/polymer.html">
<link rel="import" href="../../packages/core_elements/core_tooltip.html">
<polymer-element name="app-element">
<template>
</template>
<script type="application/dart" src="app_element.dart"></script>
</polymer-element>

Creating tab header for tabs web component using polymer-dart

I'm trying to create custom-tabs web-component using polymer-dart. The component itself is a tab container, which can have a custom-tab elements inside of it.
I want to have an html like this:
<custom-tabs selected="three">
<custom-tab name="one">... content skipped ...</custom-tab>
<custom-tab name="two">... content skipped ...</custom-tab>
<custom-tab name="three">... content skipped ...</custom-tab>
</custom-tabs>
In custom-tabs html file I want to have something like this:
<polymer-element name="custom-tabs">
<template>
<div class="tabs">
<content select="custom-tab"></content>
</div>
<nav>
For each of custom-tab I want to create tab header (link) here
</nav>
</template>
</polymer-element>
Is it possible to:
For each custom tab inserted into .tabs create link inside div?
If custom-tab element has a property named 'caption', can I get it using some kind of {{attribute-name}} syntax?
Finally I want to look the component like this:
P.S. I only need help on polymer-dart <template> syntax, I can deal with css myself. Thanks in advance!
<link rel="import" href="../../packages/polymer/polymer.html">
<polymer-element name="custom-tabs">
<template>
<style>
:host {
display: block;
}
</style>
<nav>
<template repeat="{{tab in tabHeaders}}">
<div>{{tab}}</div>
</template>
</nav>
<div class="tabs">
<content id="content" select="custom-tab"></content>
</div>
</template>
<script type="application/dart" src="custom_tabs.dart"></script>
</polymer-element>
import 'package:polymer/polymer.dart';
import 'dart:html' as dom;
#CustomTag('custom-tabs')
class CustomTabs extends PolymerElement {
CustomTabs.created() : super.created() {}
#observable
// toObservable() is to make Polymer update the headers (using template repeat) when the tabs list changes later on
List<String> tabHeaders = toObservable([]);
attached() {
super.attached();
// initialize the header list when the custom-tabs element is attached to the dom
updateTabHeaders();
}
// needs to be called every time the list of custom-tab children changes
void updateTabHeaders() {
tabHeaders.clear();
// the content element needs to have the id 'content'
($['content'] as dom.ContentElement).getDistributedNodes().forEach((e) {
// you can skip elements here for example based on attributes like 'hidden'
tabHeaders.add((e as dom.Element).attributes['name']);
});
}
}

Reference static consts from HTML

I'd like to use a const within a Dart class and reference its value in my HTML. For example:
Dart class:
Class MyClass
{
static const String MY_VALUE = "foo";
}
HTML:
<input value="{{MyClass.MY_VALUE}}">
Can we do this?
No, as far as I know, you cannot use a static const in your template. The template expects instance methods and getters. There is however an easy workaround: define a getter that returns the value of the const, and then use that getter in your HTML.
Here is the code for the getter:
String get myValue => MY_VALUE;
And here is the use of the getter in the HTML:
<input value="{{myValue}}">
I tried it because I'm new to polymer, and I don't think you can have static final class variables published/observable, but you can have final instance variables. published/observable.
// my.dart
class MyClass
{
#observable static final String MY_VALUE="foo";
}
Doesn't work but this does.
// my.dart
class MyClass
{
#observable final String MY_VALUE="foo";
}
... the rest of my rambling answer.
then
<!-- mytemplate.html -->
<polymer-element name="my-tag" >
<!-- lowercase and minus convention for html tag names -->
<template>
<input value={{MY_VALUE}}/>
</template>
<script type="application/dart" src="my.dart"/>
</polymer-element>
then go back to my.dart , add
import 'package:polymer/polymer.dart';
import 'dart:html'; // what for ? why is there single quotes ?
#CustomTag('my-tag')
// camel case , brackets, single quotes,
class MyClass {
#observable static final int MY_VALUE="foo";
// lowercase after #, no brackets, no single quotes
}
from my reading of custom polymer elements
And then finally
<!-- index.html -->
<html>
<head>
<link rel="import" href="mytemplate.html"/>
<script type="application/dart">
export 'package:polymer/init.dart';
</script>
<script src="packages/browser/dart.js" />
</head>
<body>
<my-tag></my-tag>
</body>
</html>
Looking back , there's a lot of referencing going on.
The custom html polymer element has to link to dart code,
so inside the
<polymer-element></polymer-element>
tags there is a
<script type="application/dart" src="my.dart"/>
The dart code has to link to the custom html element , so there is a
#CustomTag('my-tag')
before the class declaration.
There is also a need to import the polymer library, and the html library,
and a need to make class static constant observable.
Maybe the #observable tag only works on objects.
I tried it , and it only worked on objects,
and it didn't compile when I used the abbreviated script tag inside my.html,
so I had to do
<script type="application/dart" src="my.dart">
</script>

Passing data to a Polymer element

When working with Web UI I could pass data to a component like this:
<my-element" name="{{someName}}"></my-element>
How do I pass data to a Polymer element?
You can pass data to a Polymer element, but there is a little bit more detail involved. Imagine the element with a single field, name:
// In element.dart.
import 'package:polymer/polymer.dart';
#CustomTag("my-element")
class MyElement extends PolymerElement with ObservableMixin {
#observable String name;
}
And here is the accompanying html:
// In element.html.
<polymer-element name='my-element' attributes="name">
<template>
<h2>{{name}}</h2>
</template>
<script type="application/dart" src="element.dart"></script>
</polymer-element>
Note the attributes="name" part. That configures things so that the element can be passed the name attribute when it is created (you can pass in multiple attributes by separating them with a comma if your element needs it).
When creating the element, wrap it in a <template> tag that is bound to the values you want to pass to it:
// In index.html.
<template id='name1' bind>
<my-element name="{{}}"></my-element>
</template>
<template id='name2' bind>
<my-element name="{{}}"></my-element>
</template>
Each <template> gets bound to a separate value (we'll get to that in a second). When creating the element, you can get that value using {{}} syntax.
The data can be bound to the template in the following manner:
// In index.dart.
void main() {
query('#name1').model ='Bob';
query('#name2').model ='Rohan';
}
This way, the first <my-element> is created with the name 'Bob', and the second <my-element> is created with the name 'Rohan'.

Accessing Parent Context in Polymer.dart

I have problems accessing the parent scope inside the repeater.
The following code works:
<polymer-element name="x-playground" extends="div" attributes="children parent">
<template>
{{parent}}
<template repeat="{{children}}">
{{}}
</template>
</template>
<script type="application/dart">
import 'package:polymer/polymer.dart';
#CustomTag("x-playground")
class PlaygroundView extends PolymerElement with ObservableMixin {
#observable List children;
#observable String parent;
}
</script>
</polymer-element>
But If I replace it with the following:
<template repeat="{{children}}">
{{parent}}
</template>
it throws variable not found: parent in 770699111.
Is there a way to access the parent scope?
This is bug https://code.google.com/p/dart/issues/detail?id=12742. Please star the issue to be notified when it's fixed. Thanks for the report!

Resources