The subject line of the question is a bit ambiguous. I have an main entry file to load (entry.html) which uses a entry.dart script. In the entry.html, I use a custom polymer element card-table. cardtable.html is a simple list. When I load the entry.html first time, everything is good.. I see multiple rows of text printed with static data in my model list. My entry.html has a button, clicking which changes the data model (through entry.dart, I invoke the cardtable.dart). I see the right methods being called and data model change is confirmed, but UI is not updated.
entry.html
<link rel="import" href="cardtable.html">
<link rel="import" href="packages/paper_elements/paper_button.html">
<script async src="packages/browser/dart.js"></script>
<script async type="application/dart" src="entry.dart"></script>
<link rel="stylesheet" href="entry.css">
</head>
<body>
<paper-button id="inc_btn" label="+" raisedButton></paper-button>
<paper-button id="dec_btn" label="-" raisedButton></paper-button>
<card-table></card-table>
</body>
entry.dart
var tablec;
void main() {
initPolymer().run(() {
Polymer.onReady.then((_) {
tablec = new Element.tag('card-table');
var incBtn = querySelector('#inc_btn');
incBtn.onClick.listen(increment);
});
}
void increment(Event e) {
new Future(() {
tablec.increment();
});
}
}
card-table.html
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="card-table">
<template>
<style>
:host {
display: block;
color: green;
}
</style>
<content>
<div id="dynamic_area">
<template repeat="{{item in list}}">
<span>ABCD : {{item}}</span>
</template>
</div>
</content>
</template>
<script type="application/dart" src="cardtable.dart"></script>
</polymer-element>
cardtable.dart
#CustomTag('card-table')
class CardTable extends PolymerElement {
#observable List list = toObservable(['a', 'b', 'c']);
CardTable.created() : super.created() {
polymerCreated();
}
void increment() {
print('INCREMENT'); //is called on clicking + button on entry.html
list.add('d');
}
}
You call increment on a new <card-table> you reference using a variable, not the one inside your <body> tag.
Instead of
tablec = new Element.tag('card-table');
you use use
tablec = querySelector('card-table');
Related
Hello:
I have a paper-dialog element in a page:
<paper-dialog ... id="autom_desc_dialog" autoCloseDisabled>
...
<paper-button ... id="automatizar" affirmative autofocus disabled></paper-button>
</paper-dialog>
and I have an event listener that handles the paper-button click:
var auto_btn = querySelector('#automatizar');
auto_btn.on["click"].listen((Event e) {
// Some AJAX stuff
});
What I want is that in some cases, to be able to prevent the dialog from closing, I've tried event.preventDefault(), event.stopImmediatePropagation(), event.stopPropagation() but no success.
Thanks in advance.
You don't need to remove affirmative/dismissive attributes as they are used for layout. Polymer dialog docs are wrong (I've opened a GH issue) the default value for closeSelector is '[dismissive],[affirmative]' and not "", you just need to set closeSelector to "" and it won't close the dialog on clicking the buttons.
You just need to remove the affirmative attribute from the button then you have full control of the behavior.
app-element.dart
import 'package:polymer/polymer.dart';
import 'dart:html';
import 'package:paper_elements/paper_dialog.dart';
/**
* A Polymer app-element element.
*/
#CustomTag('app-element')
class AppElement extends PolymerElement {
/// Constructor used to create instance of AppElement.
AppElement.created() : super.created() {
}
void openClickHandler(Event e) {
print(e);
($['autom_desc_dialog'] as PaperDialog).opened = true;
}
void closeClickHandler(Event e){
if(true /* some condition */) {
($['autom_desc_dialog'] as PaperDialog).opened = false;
}
}
}
app_element.html
<!-- import polymer-element's definition -->
<link rel="import" href="../../packages/polymer/polymer.html">
<link rel="import" href="../../packages/paper_elements/paper_dialog.html">
<link rel="import" href="../../packages/paper_elements/paper_button.html">
<polymer-element name="app-element">
<template>
<style>
:host {
display: block;
}
</style>
<paper-dialog id="autom_desc_dialog" autoCloseDisabled>
<div>paper dialog</div>
<paper-button id="automatizar" autofocus label="close" on-click="{{closeClickHandler}}"></paper-button>
</paper-dialog>
<paper-button id="open" autofocus label="open" on-click="{{openClickHandler}}"></paper-button>
</template>
<script type="application/dart" src="app_element.dart"></script>
</polymer-element>
I have the following drawer-form component
drawer-form.html
<!DOCTYPE html>
<link rel="import" href="../../../packages/polymer/polymer.html">
<link rel="import" href="../../../packages/paper_elements/paper_icon_button.html">
<polymer-element name='drawer-form'>
<template>
<section id='reg' layout horizontal center>
<paper-icon-button
icon="menu"
id='menu_icon'
on-click='{{clickHandler}}'>
</paper-icon-button>
<h4 id='regLbl'>New Patient</h4>
</section>
</template>
<script type="application/dart">
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag( 'drawer-form' )
class DrawerForm extends PolymerElement {
#observable bool state = false;
DrawerForm.created() : super.created();
void clickHandler( ) {
fire( 'CREATE_NEW_PATIENT' );
}
}
</script>
</polymer-element>
The drawer-form is used in a main-form component:
main-form.html
<!DOCTYPE html>
<link rel="import" href="../../../packages/polymer/polymer.html">
<link rel="import" href="../../../packages/core_elements/core_drawer_panel.html">
<link rel="import" href="../../../packages/core_elements/core_icon_button.html">
<link rel="import" href="../../../packages/core_elements/core_toolbar.html">
<link rel="import" href="../../../packages/paper_elements/roboto.html">
<link rel="import" href="../../../packages/core_elements/core_toolbar.html">
<link rel="import" href="../../../packages/paper_elements/paper_icon_button.html">
<link rel="import" href="../../../packages/fontawesome_elements/fontawesome_icon.html">
<link rel="import" href="drawer-form.html">
<polymer-element name="main-form">
<template>
<core-drawer-panel id="core_drawer_panel">
<section id="drawer" drawer>
<drawer-form></drawer-form>
</section>
<section id="main" main>
<core-toolbar id="core_toolbar">
<paper-icon-button
icon="menu"
id='menu_icon'
on-click='{{menu_icon_handler}}'>
</paper-icon-button>
<div id="div" flex>Toolbar</div>
</core-toolbar>
<section id='content'></section>
</section>
</core-drawer-panel>
</template>
<script type="application/dart">
import 'package:polymer/polymer.dart';
import 'dart:html';
import 'package:core_elements/core_drawer_panel.dart';
#CustomTag( 'main-form' )
class MainForm extends PolymerElement {
CoreDrawerPanel drawerPanel;
MainForm.created() : super.created();
void toggleDrawer() {
bool state = drawerPanel.narrow;
}
void menu_icon_handler() {
bool state = drawerPanel.narrow;
print ( state );
}
#override
void attached() {
super.attached();
drawerPanel = $['drawerPanel'] as CoreDrawerPanel;
}
}
</script>
</polymer-element>
The clickHandloer in drawer-form.html fires a 'CREATE_NEW_PATIENT' event. How do I capture this event in the main-form component to dyanmically create the new-patient?
You should only use lowercase characters and dash for the event name (I very recently saw a bug report that this doesn't work).
I don't think anybody is able to catch an event fired from an element not yet attached to the DOM.
The constructor is therefore a bad place to put your 'fire' code to, use attached() (after super.attached()) instead.
Then you can listen in code like
// main-form
#override
void attached() {
super.attached();
this.shadowRoot.querySelector('drawer-form').on['create-new-patient'].listen((e) {
print('create-new-patient received');
}
}
or declaratively
<drawer-form on-create-new-patient='{{myEventHandlerInMainForm}}'>
When I have a reference to an element that was produced by a <template>, in Polymer.js such elements have an attribute templateInstance that provides a references to its template like it's used here:
https://github.com/PolymerLabs/polymer-selector/blob/master/polymer-selector.html#L286
Polymer >= 1.0.0
#reflectable
void someClickHandler(dom.Event event, [_]) {
// for native events (like on-click)
var model = new DomRepeatModel.fromEvent(event);
// or for custom events (like on-tap, works also for native events)
var model = new DomRepeatModel.fromEvent(convertToJs(event));
var value = model.jsElement['items'];
// or
var value = model.jsElement[$['mylist'].attributes['as']];
// if you used the `as="somename"`
// in your <core-list> or <template is="dom-repeat">
}
There is an open issue related to custom events: https://github.com/dart-lang/polymer-dart/issues/624
Polymer <= 0.16.0
EDIT
The example below needs only this 3 lines, the other code is just for demonstration purposes
import 'package:template_binding/template_binding.dart' as tb;
tb.TemplateInstance ti = tb.nodeBind(e.target).templateInstance;
var value = ti.model.value as Inner;
EDIT END
This functionality was added recently (see https://code.google.com/p/dart/issues/detail?id=17462)
I created an example to test how it works:
index.html
<!DOCTYPE html>
<html>
<head>
<title>nested-repeat</title>
<!-- <script src="packages/web_components/platform.js"></script>
not necessary anymore with Polymer >= 0.14.0 -->
<script src="packages/web_components/dart_support.js"></script>
<link rel="import" href="nested_templates.html">
</head>
<body>
<nested-templates></nested-templates>
<script type="application/dart">export 'package:polymer/init.dart';</script>
</body>
</html>
nested_templates.html
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="nested-templates">
<template>
<style>
:host { display: block; height: 100%; }
ul { margin: 0; padding: 0; }
li { font-size: 0.85rem; padding-left: 0.75rem; }
li:hover { background: lightgrey; cursor: pointer; }
li.selected { color: red; }
</style>
<div>
<template repeat="{{o in outer}}">
<strong>{{o.name}}</strong>
<ul>
<template repeat="{{i in o.inner}}">
<li id="{{i.name}}" on-click="{{innerClickHandler}}" template-value='{{i}}'>{{i.name}}</li>
</template>
</ul>
</template>
</div>
</template>
<script type="application/dart" src="nested_templates.dart"></script>
</polymer-element>
nested_templates.dart
import 'dart:html' as dom;
import 'package:polymer/polymer.dart';
import 'package:template_binding/template_binding.dart' as tb;
#CustomTag('nested-templates')
class NestedTemplates extends PolymerElement {
NestedTemplates.created() : super.created();
#observable List<Outer> outer = toObservable([new Outer('o1', toObservable(
[new Inner('a'), new Inner('b')])), new Outer('o2', toObservable([new Inner(
'c'), new Inner('d')]))], deep: true);
void innerClickHandler(dom.Event e) {
shadowRoot.querySelectorAll('li.selected').forEach((e) => (e as
dom.HtmlElement).classes.remove('selected'));
(e.target as dom.HtmlElement).classes.add('selected');
tb.TemplateInstance ti = tb.nodeBind(e.target).templateInstance; // get access to the TemplateInstance of the element
// TemplateInstance provides access to the model and the actual value
var value = ti.model.value as Inner;
print('name: ${value.name}'); // works
print('equals: ${value == (e.target as dom.HtmlElement).attributes['template-value']}'); // prints "false"
print(
'${(e.target as dom.HtmlElement).attributes['template-value']}'); // prints "Instance of 'Inner'"
// shows that the attribute only has the result of 'toString()' but not the actual value of type 'Inner'
print(
'${(e.target as dom.HtmlElement).attributes['template-value'].runtimeType}'); // prints "String"
}
}
class Inner extends Observable {
#observable String name;
Inner(this.name);
}
class Outer extends Observable {
#observable String name;
List<Inner> inner;
Outer(this.name, this.inner);
}
For the past few hours I have been struggling to refer to a sibling element within my Polymer project. Imagine the following setup:
/* main.html */
<link rel="import" href="siblingA.html">
<link rel="import" href="siblingB.html">
<polymer-element name="app-main">
<template>
<app-siblingA></app-siblingA>
<app-siblingB></app-siblingB>
</template>
<script type="application/dart" src="main.dart"></script>
</polymer-element>
/* siblingA.html, nothing special about it */
<polymer-element name="app-siblingA">
<template>
<button on-click="{{doSomething))">Do something</button>
</template>
<script type="application/dart" src="siblingA.dart"></script>
</polymer-element>
/* siblingA.dart */
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('app-siblingA')
class SiblingA extends PolymerElement {
bool get applyAuthorStyles => true;
SiblingA.created() : super.created() {
}
void doSomething(MouseEvent e, var detail, Node target) {
var profile = document.querySelector('app-siblingB');
print(profile); // This is always null, why?
}
}
Now I can get my app-main node from the document, but it fails on getting sibling elements. I have tried getting the sibling element via the shadowRoot without success.
How can I get a sibling element, in this case app-siblingB, from the document or shadowRoot?
Your siblings are within the shadowDOM of <app-main>. document.querySelector() doesn't reach into the shadowDOM of an element.
This should work
(parentNode as ShadowRoot).querySelector('app-siblingB');
I am trying to change the default web application that uses the polymer library so that the polymer element is created and added to the DOM from DART code rather than including in the HTML. I have succeeded in adding the element to the DOM, but my observable variable are not being updated on the DOM. The events are being fired, and the values are changing. I have got the DOM to update using Observable.dirtyCheck(), however, this is apparently expensive, so am trying to figure out how to get polymer to update dom without dirtyCheck().
So, In short, how to I get rid of Observable.dirtyCheck()???
dynamiccreate.dart
library dynamiccreate;
import 'dart:html';
import 'package:polymer/polymer.dart';
main() {
initPolymer();
//create click-counter element at runtime from DART, not HTML
var NewElement = new Element.tag('click-counter');
NewElement.setAttribute("count", "5");
//Add to DOM
querySelector('#sample_container_id').children.add(NewElement);
}
dynamiccreate.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sample app</title>
<link rel="stylesheet" href="dynamiccreate.css">
<!-- import the click-counter -->
<link rel="import" href="clickcounter.html">
<!-- <script type="application/dart">export 'package:polymer/init.dart';</script> -->
<script src="packages/browser/dart.js"></script>
</head>
<body>
<h1>DynamicCreate</h1>
<p>Hello world from Dart!</p>
<div id="sample_container_id">
<!-- <click-counter count="5"></click-counter> -->
</div>
<script src="dynamiccreate.dart" type="application/dart"></script>
</body>
</html>
clickcounter.dart
import 'package:polymer/polymer.dart';
/**
* A Polymer click counter element.
*/
#CustomTag('click-counter')
class ClickCounter extends PolymerElement {
#published int count = 0;
ClickCounter.created() : super.created() {
}
//increment gets called when dynamically adding object at runtime
//But does not update count on DOM
void increment() {
count++;
//Have to add this to update count in DOM
Observable.dirtyCheck(); //<<<---How do I get rid of this???
}
}
clickcounter.html
<polymer-element name="click-counter" attributes="count">
<template>
<style>
div {
font-size: 24pt;
text-align: center;
margin-top: 140px;
}
button {
font-size: 24pt;
margin-bottom: 20px;
}
</style>
<div>
<button on-click="{{increment}}">Click me</button><br>
<span>(click count: {{count}})</span>
</div>
</template>
<script type="application/dart" src="clickcounter.dart"></script>
</polymer-element>
Change your dynamiccreate.dart file to look like this, and the counter starts incrementing in the UI:
library dynamiccreate;
import 'dart:html';
import 'package:polymer/polymer.dart';
main() {
initPolymer().run(() {
var newElement = new Element.tag('click-counter');
newElement.setAttribute("count", "15");
querySelector('#sample_container_id').children.add(newElement);
});
}
Nit: name your variable newElement, not NewElement. Fixed here.