I'm trying to nesting in Dart PolymerElements in another PolymerElement like this.
#CustomTag('test-box')
class Box extends PolymerElement{
#observable List<Child> childs = new List<Child>();
Box.created() : super.created() { }
}
#CustomTag('test-child')
class Child extends PolymerElement{
Child.created() : super.created() { }
}
and then in testbox.html
<link rel="import" href="testchild.html">
<polymer-element name="test-box">
<template>
<div>
<ol name="child-list">
<template repeat="{{child in childs}}">
{{child}}
</template>
</ol>
</div>
</template>
<script type="application/dart" src="testbox.dart"></script>
</polymer-element>
Is that possible with Dart/Polymer? All my tries are failed.
I want to handle html nodes like classes.
Thanks in advance
You can use a model object to pass data to a child element via published property.
Check this example: https://github.com/sethladd/dart-polymer-dart-examples/tree/master/web/observable_objects_inside_list_changes
You can add the children nodes to the box, for example:
#CustomTag('test-box')
class Box extends PolymerElement{
#observable List<Child> childs = new List<Child>();
Box.created() : super.created() {
}
void _addChildren(List<Child> children) {
children.forEach((Child c) {
this.children.add(c);
}
}
#override void attached() { super.attached(); _addChildren(childs); }
}
Then you can monitor changes on childs using observable API to reflect the changes on the array.
Beware that Child object should be created with new Element.tag("test-child").
But IMHO the best solution is the one offered by #Leksat using a more pure MVC approach.
I had pretty much the same problem and solved it using some kind of proxy element.
ProxyElement Dart code:
library ProxyElement;
import 'package:polymer/polymer.dart';
#CustomTag('proxy-element')
class ProxyElement extends PolymerElement {
#published PolymerElement target;
ProxyElement.created() : super.created();
attached() {
shadowRoot.querySelector('#proxy').append(target);
}
}
And its HTML code:
<link rel="import" href="../packages/polymer/polymer.html">
<polymer-element name="proxy-element">
<template>
<style>
:host {
display: inline;
}
</style>
<template if="{{target == null}}">
No target element defined.
</template>
<template if="{{target != null}}">
<div id="proxy"></div>
</template>
</template>
<script type="application/dart" src="proxy_element.dart"></script>
</polymer-element>
Usage:
...
<template repeat="{{child in children}}">
<proxy-element target="{{child}}"></proxy-element>
</template>
...
Related
I want to detect attribute change, then to refresh the element.
I do
main.dart
library main;
import "package:polymer/polymer.dart";
import "dart:html";
void main() {
initPolymer().run(() {
Polymer.onReady.then((e) {
querySelector("nav-bar").setAttribute("mode", "ok");
});
});
}
navbar.html
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="nav-bar" attributes="mode">
<template if="{{mode == null}}">
<p>Hello</p>
</template>
<template if="{{mode == 'ok'}}">
<p>Youpie</p>
</template>
<script type="application/dart" src="navbar.dart"></script>
</polymer-element>
navbar.dart
import 'package:polymer/polymer.dart';
#CustomTag('nav-bar')
class NavBar extends PolymerElement {
#published String mode;
NavBar.created() : super.created();
}
When I put my element in index.html, whatever "mode" value, I have always Hello.
When I change the mode using query, nothing happen. The text should be changed...
I did something wrong ?
There are two ways that should solve the problem
querySelector("nav-bar").mode = "ok");
or
#PublishedProperty(reflect: true) String mode;
or both (in my opinion it would be best to apply both)
Do you know how to use multiple "polymer-element" with only one Dart script ?
I succeeded but I am not sure it is the best solution.
My example is a Dart/Polymer implementation of this following example with Dart/WebUI:
https://www.dartlang.org/articles/web-ui/#loops
It displays a list of fruits in a polymer-element ("example-template1"), and where we can research a specific fruit in another polymer-element ("example-template2"). The second polymer-element must update the first with data binding.
To do that, I declared as follow my polymer elements. One parent polymer-element named "example-script" (because we can only use one script declaration in a polymer templates file), and children that extend from this parent :
<polymer-element name="example-script">
<script type="application/dart" src="tute.dart"></script>
</polymer-element>
<polymer-element name="example-template1" extends="example-script">
<template>
<div>
<p>Search fruit</p>
<input type="text" class="form-control" value="{{ research }}" on-input="{{ get_results }}">
</div>
</template>
</polymer-element>
<polymer-element name="example-template2" extends="example-script">
<template>
<div><ul>
<template repeat="{{ fruit in fruits }}">
<li>{{ fruit }}</li>
</template>
</ul></div>
</template>
</polymer-element>
My Dart script is as follow:
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('example-script')
class FruitsScript extends PolymerElement {
static List<String> fruitsList = new List();
#observable static List<String> fruits = toObservable(fruitsList);
#observable static String research = '';
FruitsScript.created() : super.created();
}
#CustomTag('example-template1')
class FruitsResearch extends FruitsScript {
FruitsResearch.created() : super.created();
String get research {
return FruitsScript.research;
}
String set research(String search) {
FruitsScript.research = search;
}
void get_results(Event e, var detail, Node target) {
FruitsScript.fruits.clear();
if (FruitsScript.research.length > 0) {
var lResearch = FruitsScript.research.toLowerCase();
var results = FruitsScript.fruitsList.where((v) => v.toLowerCase().contains(lResearch));
FruitsScript.fruits.addAll(results);
}
else {
FruitsScript.fruits.addAll(FruitsScript.fruitsList);
}
}
}
#CustomTag('example-template2')
class FruitsDisplay extends FruitsScript {
FruitsDisplay.created() : super.created() {
List<String> fruits = [ 'Apple', 'Apricot', 'Avocado'];
FruitsScript.fruitsList.clear();
FruitsScript.fruitsList.addAll(fruits);
FruitsScript.fruitsList.sort();
FruitsScript.fruits.clear();
FruitsScript.fruits.addAll(FruitsScript.fruitsList);
}
List<String> get fruits {
return FruitsScript.fruits;
}
}
I declare one parent Class "FruitsScript" to initialize the observable variables. Then, I create two other classes for my two polymer elements "example-template1/2". Hence I can access to my observable variables. But for that, I also need to declare them as static, and to make setters an getters in my subclasses, otherwise my polymer elements can not share the observable variables.
This method works, but do you think there is a better way to make this?
How do you add those elements to your page?
As far as I understand what you want to to, inheritance (extend) is not the appropriate solution.
I have not tried to run this code just edited your code here in the textfield.
If this is what you want to do but something doesn't work post a comment.
I didn't want to put to much time in it as long as it's not clear what exactly you want to achieve.
In your web page you lay out your elements like this:
<example-template1></example-template1>
<example-template2></example-template2>
<example-script></example-script>
Your elements
<polymer-element name="example-script">
<script type="application/dart" src="tute.dart"></script>
</polymer-element>
<polymer-element name="example-template1">
<template>
<div>
<p>Search fruit</p>
<input type="text" class="form-control" value="{{ model.research }}" on-input="{{ get_results }}">
</div>
</template>
</polymer-element>
<polymer-element name="example-template2">
<template>
<div><ul>
<template repeat="{{ fruit in model.fruits }}">
<li>{{ fruit }}</li>
</template>
</ul></div>
</template>
</polymer-element>
Your Dart script is as follow:
import 'package:polymer/polymer.dart';
import 'dart:html';
class Model extends Object with Observable {
#observable List<String> fruits = toObservable(new List<String>());
#observable String research = '';
}
#CustomTag('example-script')
class FruitsScript extends PolymerElement {
#published Model model = new Model();
FruitsScript.created() : super.created();
void attached() {
super.attached();
(document.querySelector('example-template1') as FruitsResearch).model = model;
(document.querySelector('example-template2') as FruitsDisplay).model = model;
}
}
#CustomTag('example-template1')
class FruitsResearch extends PolymerElement {
FruitsResearch.created() : super.created();
#published Model model;
void get_results(Event e, var detail, Node target) {
if (this.research.length > 0) {
var lResearch = this.model.research.toLowerCase();
var results = this.model.fruits.where((v) => v.toLowerCase().contains(lResearch));
this.model.fruits = toObservable(results);
}
}
}
#CustomTag('example-template2')
class FruitsDisplay extends PolymerElement {
#published Model model = new Model();
FruitsDisplay.created() : super.created() {
this.model.fruits = toObservable([ 'Apple', 'Apricot', 'Avocado']);
this.model.fruits.sort();
}
}
In the following example, when the Update Class button is clicked, {{testClass.someProperty}} is updated with the new class' someProperty, but updating testClass.someProperty does not update {{testClass.someProperty}} in the template.
I thought making the TestClass #observable would make its properties observable and when updating the property, the property in the template would change.
What would be the correct way to bind TestElement.testClass.someProperty to {{testClass.someProperty}}, and as an extension, any class' properties to a Polymer Element template?
test_class.dart
library test;
import "package:polymer/polymer.dart";
#observable
class TestClass extends ObservableBase {
String someProperty;
TestClass(this.someProperty);
}
test_element.dart:
library test_element;
import "package:polymer/polymer.dart";
import "test_class.dart";
#CustomTag("test-element")
class TestElement extends PolymerElement with ObservableMixin {
#observable
TestClass testClass = new TestClass("original");
void updateClass() {
testClass = new TestClass("xyz");
}
void updateProperty() {
testClass.someProperty = "foobar";
}
}
test_element.html
<polymer-element name="test-element">
<template>
{{testClass.someProperty}}
<button on-click="updateProperty">Update Property</button>
<button on-click="updateClass">Update Class</button>
</template>
<script type="application/dart" src="test_element.dart"></script>
</polymer-element>
test.dart
library test;
int main() {
}
test.html:
<!DOCTYPE html>
<html>
<head>
<link rel="import" href="test_element.html" />
<script src="packages/polymer/boot.js"></script>
</head>
<body>
<test-element></test-element>
<script type="application/dart" src="test.dart"></script>
</body>
</html>
I got it to work by moving #observable from the class to the property. I thought annotating the class with #observable was supposed to be the same as annotating all the properties as observable, but that didn't work:
test.dart
library test;
import "package:polymer/polymer.dart";
class TestClass extends ObservableBase {
#observable
String someProperty;
TestClass(this.someProperty);
}
In Dart's Web UI, it was possible to pass arbitrary data to function in response to events, for example, the following snippet passes the value 2 to the increment(int incBy) method in response to the button's on-click event:
<!-- Web UI -->
<element name="x-click-counter">
<template>
<button on-click="increment(2)"> <!-- passing a value of 2 -->
Click me
</button>
</template>
</element>
<script>
import 'package:web_ui/web_ui.dart';
class CounterComponent extends WebComponent {
void increment(int incBy) { // accept the value of 2
count = count + incBy;
}
}
</script>
In Polymer (and Polymer.dart), the on-click event attribute requires a string version of the function name, rather than an actual function call. This is described on the polymer docs page as:
The value of an event handler attribute is the string name of a method
on the component. Unlike traditional syntax, you cannot put executable
code in the attribute.
Using polymer.dart, this looks like:
<polymer-element name="x-click-counter">
<template>
<button on-click="increment"> <!-- can't pass a value of 2, as you need to pass a string -->
Click Me
</button>
</template>
</polymer-element>
<script>
import 'package:polymer/polymer.dart';
#CustomTag("x-click-counter")
class CounterComponent extends PolymerElement with ObservableMixin {
#observable int count = 0;
void increment(Event event, var detail, var target) { // How do I pass 2 to this function?
count = count ++;
}
}
</script>
Question: How do I pass an arbitrary value to the increment function?
You can use html data- attributes to pass extra data, and then access them through the target parameter.
Re-writing the polymer example to add a data-incby field that takes the value increment the count by looks like this:
<polymer-element name="x-click-counter">
<template>
<button on-click="increment" data-incby="2"> <!-- now passing the value as a data attribute -->
Click Me
</button>
</template>
</polymer-element>
<script>
import 'package:polymer/polymer.dart';
#CustomTag("x-click-counter")
class CounterComponent extends PolymerElement with ObservableMixin {
#observable int count = 0;
void increment(Event event, var detail, var target) {
int incBy = int.parse(target.attributes['data-incby']); // extract the value 2
count = count + incBy;
}
}
</script>
Dart and Polymer.dart have changed since Chris' answer. Here is updated code for Dart v1.0:
<polymer-element name="x-click-counter">
<template>
<button on-click="{{increment}}" data-incby="2"> <!-- now passing the value as a data attribute -->
Click Me
</button>
<span>{{count}}</span>
</template>
</polymer-element>
<script type="application/dart">
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag("x-click-counter")
class CounterComponent extends PolymerElement {
#observable int count = 0;
CounterComponent.created() : super.created();
void increment(Event event, var detail, var target) {
int incBy = int.parse(target.attributes['data-incby']); // extract the value 2
count = count + incBy;
}
}
</script>
My solution for Polymer 0.11.0+5
element.html
<link rel="import" href="../packages/polymer/polymer.html">
<polymer-element name="dp-element">
<template>
<div class="row">
<ul>
<template repeat="{{ item in items }}">
<li on-click="{{load}}" data-incby="{{item}}">{{ item }}</li>
</template>
</ul>
</template>
<script type="application/dart">
import 'package:polymer/polymer.dart';
import 'view.dart';
import 'dart:html';
#CustomTag('dp-element')
class DpElement extends PolymerElement {
#observable List<String> items;
DpElement.created() : super.created(){
}
void load(Event event, var detail, var target) {
String incBy = target.attributes['data-incby'];
print(incBy);
}
}
I have a class field that is a String and I want to use a text input to modify that field. How can I use #observable with polymer.dart to do this?
Here is the class field I would like to sync-up with the UI:
class Person {
#observable String name;
Person(this.name);
}
Import the polymer.dart file and mix in the ObservableMixin into Person. Extend PolymerElement, and also use a #CustomTag annotation.
Here is what the dart file using #observable with a custom element could look like:
import 'package:polymer/polymer.dart';
class Person extends Object with ObservableMixin {
#observable String name;
Person(this.name);
}
#CustomTag("custom-element")
class CustomElement extends PolymerElement {
#observable Person person = new Person('John');
}
In the associated .html file, use {{}} syntax to create the binding with the #observable field:
<!DOCTYPE html>
<html>
<body>
<polymer-element name="custom-element">
<template>
<label> Name: <input value="{{person.name}}"></label>
<p>The name is {{person.name}}</p>
</template>
<script type="application/dart" src="element.dart"></script>
</polymer-element>
</body>
</html>
This element can be used in the following manner (note the link to boot.js):
<!DOCTYPE html>
<html>
<head>
<title>index</title>
<link rel="import" href="element.html">
<script src="packages/polymer/boot.js"></script>
</head>
<body>
<custom-element></custom-element>
<script type="application/dart">
void main() {}
</script>
</body>
</html>