I have a custom element which toggles hidden states of a span and an input element when clicked so that the user perceives that the span is replaced by the input each time he clicks it.
I want the input to toggle back to hidden state and span to visible state when the input loses focus.
However, once the input is revealed and given the focus, exiting the field (e.g., by clicking outside), the blur handler method is not triggered the first time. On repeating the process the second time, the blur is triggered. For the method to fire, one has to enter the field twice, each time.
How to avoid the need for entering into the input field twice to trigger the on-blur event?
I include my code.
index.html
<!DOCTYPE html>
<html>
<head lang="en">
<link rel="import" href="packages/polymer/polymer.html">
<link rel="import" href="toggle_el.html">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<toggle-el></toggle-el>
<script type="application/dart" src='main.dart'></script>
</body>
</html>
I am initializing polymer from the main.dart
import 'package:polymer/polymer.dart';
main() {
initPolymer();
}
Custom Element html file: toggle_el.html
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="toggle-el">
<template>
<span hidden?="{{editMode}}"
on-click="{{switchEdit}}" id="name">{{name}}</span>
<input id="nmInput" hidden?="{{!editMode}}"
on-blur="{{switchEdit}}" type="text"
value="{{name}}"/>
</template>
<script type="application/dart" src="toggle_el.dart"></script>
</polymer-element>
Custom Element dart file: toggle_el.dart
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('toggle-el')
class toggleElement extends PolymerElement {
#observable String name = 'Dartgnan';
#observable bool editMode = false;
toggleElement.created() : super.created();
#override ready();
void switchEdit(Event ev, var detail, Node sender) {
editMode = !editMode;
print('edit mode is now ${editMode ? 'on' : 'off'}');
if (editMode) {
InputElement el = $['nmInput'];
el.focus();
el.selectionStart = 0;
el.selectionEnd = 999;
}
}
}
Just change el.focus(); to new Future(() => el.focus());.
This way you delay focus a bit and allow the InputElement to get unhidden before focus() is called.
Related
Since polymer-body has been removed, we need to use an auto-binded template to use polymer binding features outside of a PolymerElement:
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sample app</title>
<script src="packages/web_components/platform.js"></script>
<script src="packages/web_components/dart_support.js"></script>
<link rel="import" href="packages/polymer/polymer.html">
<script src="packages/browser/dart.js"></script>
</head>
<body>
<template is="auto-binding-dart">
<div>Say something: <input value="{{value}}"></div>
<div>You said: {{value}}</div>
<button id="mybutton" on-tap="{{buttonTap}}">Tap me!</button>
</template>
<script type="application/dart">
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'package:template_binding/template_binding.dart';
main() {
initPolymer().run(() {
Polymer.onReady.then((_) {
var template = document.querySelector('template');
templateBind(template).model = new MyModel();
});
});
}
class MyModel extends Observable {
//$['mybutton'] wont works there
#observable String value = 'something';
buttonTap() => print('tap!');
}
</script>
</body>
</html>
Unfortunately, the whole model now extends Observable, every binding seems to work, but the PolymerElement array selector $['foo'] cant be used anymore...
Is there any easy way to implement this $['id'] selector into an Observable model?
I would suggest to use a normal Polymer element instead of auto-binding-dart.
Then you don't have to care about differences and you need no 'main'.
I always start a Polymer project with an <app-element> Polymer element that acts as main() and container for the entire app.
I also would suggest to not use inline code.
As far as I know it has some limitations especially debugging is not supported (might be fixed already, I don't know because I never use it).
To make $ work you need a small and simple workaround;
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'package:template_binding/template_binding.dart';
Map<String, dynamic> $; // we define our own '$'
main() {
initPolymer().run(() {
Polymer.onReady.then((_) {
var template = document.querySelector('template') as Polymer;
$ = template.$; // we assign template.$ to our own '$' so we can omit the 'template' part
templateBind(template).model = new MyModel();
});
});
}
class MyModel extends Observable {
//$['mybutton'] wont work there - it can't because this is outside of a method
#observable String value = 'something';
buttonTap() {
print($['mybutton'].id); // here it works
print('tap!');
}
}
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>
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');
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 started with the generating click-counter example. I made the click-counter into a library which I then imported into my main file. The click-counter component can be added manually by putting the appropriate HTML into the web page before running the program. However, I've been unable to find a way to dynamically add the click-counter web component to a div. My attempts have either ended in "Aw, snap!" errors or simply with nothing happening.
The click-counter (xclickcounter.dart):
library clickcounter;
import 'package:web_ui/web_ui.dart';
class CounterComponent extends WebComponent {
int count = 0;
void increment() {
count++;
}
}
The main HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sample app</title>
<link rel="stylesheet" href="test1.css">
<!-- import the click-counter -->
<link rel="components" href="xclickcounter.html">
</head>
<body>
<h1>Test1</h1>
<p>Hello world from Dart!</p>
<div id="sample_container_id">
<div is="x-click-counter" id="click_counter" count="{{startingCount}}"></div>
</div>
<script type="application/dart" src="test1.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
main file:
import 'dart:html';
import 'package:web_ui/web_ui.dart';
import 'xclickcounter.dart';
// initial value for click-counter
int startingCount = 5;
void main() {
// no error for adding an empty button
var button = new ButtonElement();
query('#sample_container_id').append(button);
// doesn't work (gives "Aw, snap!" in Dartium)
query('#sample_container_id').append(new CounterComponent());
// Nothing happens with this code. Nothing appears.
// But I promise this same thing was giving Aw, Snap
// for a very similar program
final newComponentHtml = '<div is="x-click-counter"></div>';
query('#sample_container_id').appendHtml(newComponentHtml);
}
I tried added an empty constructor to click-counter but it still crashes.
I had the same issue.
See the example (not mine) at https://github.com/dart-lang/web-ui/blob/master/test/data/input/component_created_in_code_test.html and let me know if it works for you.
TL;DR:
void main() {
var element = query('#sample_container_id');
appendComponentToElement(element, new CounterComponent() );
}
void appendComponentToElement(Element element, WebComponent component) {
component.host = new DivElement();
var lifecycleCaller = new ComponentItem(component)..create();
element.append(component.host);
lifecycleCaller.insert();
}
There's more info at my web-ui#dartlang.org post: https://groups.google.com/a/dartlang.org/d/topic/web-ui/hACXh69UqG4/discussion
Hope that helps.