How to retrieve the current input in a paper-dropdown-menu - dart

I have the following snippets of a paper-dropdown-menu
.dart
....
#property
List<String> suffixes = <String>[
'I',
'II',
'III',
'Junior',
'Senior'
];
.html
<paper-dropdown-menu label = "Suffix">
<paper-menu class = "dropdown-content">
<template is = "dom-repeat"
items = "[[suffixes]]"
as = "suffix">
<paper-item>[[suffix]]</paper-item>
</template>
</paper-menu>
</paper-dropdown-menu>
What is the correct .dart code to get the selection made in the dropdown?
Thanks

There are several ways to achieve this.
The example below shows two ways using selected-item and selected-item-label
.html
<!DOCTYPE html>
<dom-module id='app-element'>
<template>
<paper-dropdown-menu label = "Suffix"
selected-item="{{selectedItem}}">
<paper-menu class = "dropdown-content">
<template id="ddmtr" is="dom-repeat"
items="[[suffixes]]"
as="suffix">
<paper-item label="suffix">[[suffix]]</paper-item>
</template>
</paper-menu>
</paper-dropdown-menu>
<div>selectedItem:<span>[[selectedItem]]</span> value: <span>[[selectedItemValue]]</span></div>
<paper-dropdown-menu label = "Suffix"
selected-item-label="{{selectedItemLabel}}">
<paper-menu class = "dropdown-content">
<template is="dom-repeat"
items="[[suffixes]]"
as="suffix">
<paper-item>[[suffix]]</paper-item>
<!-- <paper-item label="suffix">[[suffix]]</paper-item> -->
<!-- if the label attribute is not set, the text content is used -->
</template>
</paper-menu>
</paper-dropdown-menu>
<div>selectedItemLabel:<span>[[selectedItemLabel]]</span></div>
</template>
</dom-module>
.dart
#HtmlImport('app_element.html')
library so33770938_paper_dropdown_menu_selected.web.app_element;
import 'dart:html' as dom;
import 'package:web_components/web_components.dart' show HtmlImport;
import 'package:polymer/polymer.dart';
import 'package:polymer_elements/paper_dropdown_menu.dart';
import 'package:polymer_elements/paper_menu.dart';
import 'package:polymer_elements/paper_item.dart';
/// [PaperDropdownMenu], [PaperMenu], [PaperItem]
#PolymerRegister('app-element')
class AppElement extends PolymerElement {
AppElement.created() : super.created();
#property var selectedItem;
#property var selectedItemLabel;
#Property(computed: 'getSelectedItemValue(selectedItem)')
String selectedItemValue;
#reflectable
String getSelectedItemValue(dom.Element selectedItem) {
DomRepeatModel model =
($['ddmtr'] as DomRepeat).modelForElement(selectedItem);
return suffixes[model.index];
}
#property
List<String> suffixes = <String>[
'I',
'II',
'III',
'Junior',
'Senior'
];
}

Related

Setting a hidden attribute in dart-polymer 1.x

I am trying to toggle (hide/unhide> a state dropdown menu when the USA is selected in a country dropdown menu
.html
<paper-dropdown-menu
label = "Country *"
selected-item-label = "{{countrySelectedItemLabel}}"
error-message = "Country is required"
id = "countryDdm">
<paper-menu class = "dropdown-content">
<template
is = "dom-repeat"
items = "[[countries]]"
as = "country">
<div>[[country.name]]</div>
<br>
</template>
</paper-menu>
</paper-dropdown-menu>
<div class = "layout horizontal">
<paper-dropdown-menu
hidden = $"[[hideState]]"
label = "State *"
selected-item-label = "{{stateSelectedItemLabel}}"
id = "stateDdm">
<paper-menu class = "dropdown-content">
<template
is = "dom-repeat"
items = "[[states]]"
as = "state">
<div>[[state.name]]</div>
<br>
</template>
</paper-menu>
</paper-dropdown-menu>
The relevant .dart code is shown below
##.dart
#property
bool hideState;
#property
String countrySelectedItemLabel = '';
#Listen( 'countryDdm.tap' )
void toggleStateOnUSASelection( event, [_] ) {
switch ( countrySelectedItemLabel ) {
case 'United States of America':
switch ( hideState ) {
case true:
hideState = false;
break;
case false:
break;
}
break;
}
}
void ready( ) {
set('hideState', true);
}
The application is displayed normally but when I select 'United States of America' the state combo is NOT shown. I would also like to hide the state combo if any country than the USA is selected.
Any help is appreciated. Thanks.
The $ is on the wrong position
hidden$="[[hideState]]"
The actual hidden attribute is set by Polymer. This is to work around issues with attributes like href of the <img> element where binding expressions (strings that aren't an actual URI to an image) would produce an error message before Polymer even had a chance to resolve the binding expression.
There are a few further issues (see the comments in the code)
dart
#HtmlImport('app_element.html')
library so33931432_hide_paper_dropdown.web.app_element;
import 'package:web_components/web_components.dart' show HtmlImport;
import 'package:polymer/polymer.dart';
import 'package:polymer_elements/paper_dropdown_menu.dart';
import 'package:polymer_elements/paper_menu.dart';
/// [PaperDropdownMenu], [PaperMenu]
#PolymerRegister('app-element')
class AppElement extends PolymerElement {
AppElement.created() : super.created();
#property
List<String> countries = ['Austria', 'Belgium', 'Czech Republic', 'United States of America'];
#property
bool hideState; // = true; // you could set a default value, then you don't need ready
// This way usually works better for me than #Listen
#Property(observer: 'toggleStateOnUSASelection')
String countrySelectedItemLabel = '';
// If `#Property(observer: ...) is used the function signature
// has to be changed
#reflectable
void toggleStateOnUSASelection(String label, [_]) {
switch (countrySelectedItemLabel) {
// I wasn't sure what you actually tried to accomplish here
// but this worked for me to reproduce your problem
case 'United States of America':
set('hideState', false);
break;
default:
set('hideState', true);
}
}
void ready() {
set('hideState', true);
}
}
html
<!DOCTYPE html>
<dom-module id='app-element'>
<template>
<paper-dropdown-menu
label="Country *"
selected-item-label="{{countrySelectedItemLabel}}"
error-message="Country is required"
id="countryDdm">
<paper-menu class="dropdown-content">
<template
is="dom-repeat"
items="[[countries]]"
as="country">
<div label="[[country]]">[[country]]</div>
</template>
</paper-menu>
</paper-dropdown-menu>
<div>selectedItem:<span>[[countrySelectedItemLabel]]</span> value: <span>[[countrySelectedItemLabel]]</span></div>
<div>hideState: <span>[[hideState]]</span></div>
<div class="layout horizontal">
<paper-dropdown-menu
hidden$="[[hideState]]"
label="State *"
selected-item-label="{{stateSelectedItemLabel}}"
id="stateDdm">
<paper-menu class="dropdown-content">
<template
is="dom-repeat"
items="[[states]]"
as="state">
<div>[[state.name]]</div>
<br>
</template>
</paper-menu>
</paper-dropdown-menu>
</div> <!-- missing in your question -->
</template>
</dom-module>

Polymer linkPaths does not fire on-change et all

EDITED: NOW WITH COMPLETE CODE
Previous Post related
LinkPaths works, but does not fire all on-change event of the elements where the data changed. See the image:
For example, when data is changed on <paper-input label="Produto" value="{{item.descricao}}"></paper-input> (outer dom-repeat) the data in element <paper-input label="Produto Componente" value="{{item_comp.descricao}}" on-change="mudou"></paper-input> (inner dom-repeat) change too. It´s works nice because of the linkPaths!
But on-change="mudou" does not fire.
Just fire if data entry directly on <paper-input label="Produto Componente" value="{{item_comp.descricao}}" on-change="mudou"></paper-input> (inner dom-repeat)
main_app.html
<dom-module id="main-app">
<style>
:host {
display: block;
}
</style>
<template>
<h3>Lista de Produtos</h3>
<template is="dom-repeat" items="{{produtos}}" as="item">
<div class="layout vertical">
<paper-material elevation="1">
<div class="layout horizontal">
<paper-input label="Produto" value="{{item.descricao}}"></paper-input>
</div>
</paper-material>
<template is="dom-repeat" items="{{item.componentes}}" as="item_comp">
<div class="layout vertical">
<div class="layout horizontal">
<paper-input label="Produto Componente" value="{{item_comp.descricao}}" on-change="mudou"></paper-input>
</div>
</div>
</template>
</div>
</template>
</template>
</dom-module>
main_app.dart
import 'dart:html';
import 'package:polymer_elements/paper_input.dart';
import 'package:polymer_elements/paper_fab.dart';
import 'package:polymer_elements/iron_icons.dart';
import 'package:polymer_elements/paper_material.dart';
import 'package:polymer/polymer.dart';
import 'package:web_components/web_components.dart';
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
#Property(notify: true)
List<Produto> produtos = new List();
MainApp.created() : super.created();
void ready() {
Produto p = new Produto()..descricao = 'componente 1';
add('produtos', p);
Produto p2 = new Produto()..descricao = 'componente 2';
add('produtos', p2);
Produto p3 = new Produto()..descricao = 'composto';
add('produtos', p3);
add('produtos.2.componentes', p);
add('produtos.2.componentes', p2);
linkPaths('produtos.2.componentes.0', 'produtos.#0');
linkPaths('produtos.2.componentes.1', 'produtos.#1');
linkPaths('produtos.0', 'produtos.#2.componentes.#0');
linkPaths('produtos.1', 'produtos.#2.componentes.#1');
}
#reflectable
void adicionarProduto(e, d) {
//...
}
#reflectable
mudou(e, d) {
window.alert('teste');
}
}
class Produto extends JsProxy {
#reflectable
String descricao;
#reflectable
List<Produto> componentes;
Produto() {
componentes = new List();
}
}
Is this normal in Polymer? How I can to force fire on-change?
I found a workaround solution.
I used computed binding method, no more on-change event. This form, I passed the paper-input value reference on method call, and all time that value change, the method is called.
The code changed:
.html
...
<paper-input label="Produto Componente" value="{{item_comp.descricao}}"></paper-input>
<span>{{mudou(item_comp.descricao)}}</span>
...
.dart
...
#reflectable
void mudou(a) {
window.alert('teste');
}
...

Creating a custom Polymer element

I'm trying to create a custom Polymer element that extends paper-shadow to display a Tweet.
Here is my implementation:
tweet_element.html
<link rel="import" href="packages/paper_elements/paper_shadow.html">
<link rel="import" href="packages/polymer/polymer.html">
<link rel="stylesheet" href="tweet_element.css">
<polymer-element name="tweet-element" extends="paper-shadow">
<template>
<div id="header">
<div id="user-image">
<img src="{{userImageUrl}}">
</div>
<div id="details">
<div id="user">{{user}}</div>
<div id="date-published">{{datePublished}}</div>
</div>
</div>
<div id="content">
<div id="text">{{text}}</div>
<div id="photos">{{photos}}</div>
</div>
</template>
<script type="application/dart" src="twitter.dart"></script>
</polymer-element>
twitter.dart
import 'package:polymer/polymer.dart';
#CustomTag('tweet-element')
class TweetElement extends PolymerElement {
#Observable String userImageUrl;
#Observable String user;
#Observable String datePublished;
#Observable String text;
TweetElement.created() : super.created();
void update(Tweet tweet) {
userImageUrl = tweet.user.profileImage;
user = '${tweet.user.name} (#${tweet.user.screenName})';
datePublished = _parseDate(tweet.date);
text = tweet.text;
}
...
}
And finally the code that creates a TweetElement and tries to add it to the DOM:
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'twitter.dart';
...
var mainContent = querySelector('#main-content');
var element;
for (var tweet in tweets) {
element = new TweetElement.created();
element.update(tweet);
mainContent.children.add(element);
}
And when I run this I get:
Exception: Uncaught Error: created called outside of custom element creation.
So then I tried to change twitter.dart to:
TweetElement.created() : super.created();
TweetElement (Tweet tweet) {
TweetElement.created();
userImageUrl = tweet.user.profileImage;
user = '${tweet.user.name} (#${tweet.user.screenName})';
datePublished = _parseDate(tweet.date);
text = tweet.text;
}
And add the element to the DOM like this:
var mainContent = querySelector('#main-content');
var element;
for (var tweet in tweets) {
element = new TweetElement(tweet);
mainContent.children.add(element);
}
And now I got this error:
Internal error: unresolved implicit call to super constructor 'PolymerElement()' TweetElement (Tweet tweet) {
Ralph.
You can do that in two ways:
Option A
If you want to create a Polymer Element in your Dart code, you just have to create that tag this way:
var myTweetElement = new Element.tag ('tweet-element');
mainContent.childern.add(myTweetElement);
Also, check that you have imported the html library:
import 'dart:html';
Option B: (the coolest one)
You can do it extra convenient (and more object oriented) by adding this factory to your twitter.dart:
factory TweetElement () => new Element.tag('tweet-element');
Then, the creation of the tag in your dart code, is more readable:
var myTweetElement = new TweetElement (); // This uses the factory transparently
mainContent.children.add(myTweetElement);
Additionally, you can set the values of your properties. As those are observable, the bindings will update automagically:
myTweetElement.userImageUrl = "foo"
myTweetElement.user = "bar"
myTweetElement.datePublished = "baz"
myTweetElement.text = "qux"
Or if you like the cascade operator, you can write this instead:
myTweetElement..userImageUrl = "foo"
..user = "bar"
..datePublished = "baz"
..text = "qux";
Hope this helps.

Template data binding

I'm trying to create a custom element with data binding.
Here is my custom element template:
<link rel="import" href="packages/paper_elements/paper_shadow.html">
<link rel="import" href="packages/polymer/polymer.html">
<polymer-element name="tweet-element">
<template>
<link rel="stylesheet" href="tweet_element.css">
<paper-shadow z="1">
<div id="header" horizontal layout>
<div id="user-image">
<img _src="{{profileImage}}">
</div>
<div id="user-details" flex>
<div horizontal layout>
<div id="name">{{name}}</div>
<div id="screen-name">(#{{screenName}})</div>
</div>
<div id="date-published">{{date}}</div>
</div>
</div>
<div id="content">
<div id="text">{{text}}</div>
</div>
</paper-shadow>
</template>
<script type="application/dart" src="twitter.dart"></script>
</polymer-element>
twitter.dart
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'package:polymer_expressions/polymer_expressions.dart';
#CustomTag('tweet-element')
class TweetElement extends PolymerElement {
#Observable String profileImage;
#Observable String name;
#Observable String screenName;
#Observable String date;
#Observable String text;
TweetElement.created() : super.created();
factory TweetElement() => new Element.tag('tweet-element');
}
This is how I'm creating and adding the elements:
main.dart
import 'dart:html';
import 'package:polymer/polymer.dart';
import 'package:polymer_expressions/polymer_expressions.dart';
import 'twitter.dart';
void main() {
...
var mainContent = querySelector('#main-content');
var element;
for (var tweet in tweets) {
element = new TweetElement();
element
..profileImage = tweet.user.profileImage
..name = tweet.user.name
..screenName = tweet.user.screenName
..date = _parseDate(tweet.date)
..text = tweet.text;
mainContent.children.add(element);
}
}
The tweet-element elements and being added to the DOM, but the fields with data binding are blank:
There is no problem with the tweet objects, because I've tried setting the element fields with other Strings and it also didn't work.
If you have a custom main method in a Polymer.dart application, you need to take care of Polymer initialization yourself.
See how to implement a main function in polymer apps for more details.
I managed to solve the problem. I was using the #Observable tag instead of #observable (notice upper/lowercase letters).

How to update the view on property change of objects in ObservableMap?

I have an observable map, which maps arbitrary objects (say another maps) to their id's. When I make changes to these objects, the objects should be updated in the view, too. However, I didn't get it to work. Here is my setup so far:
myexample.html
<polymer-element name="my-example">
<script type="application/dart" src="myexample.dart"></script>
<template>
<style></style>
<div>
<ul>
<template repeat="{{ entry in map.values }}">
<li>{{ entry }}</li>
</template>
</ul>
<button on-click="{{change}}">Change</button>
</div>
</template>
</polymer-element>
myexample.dart
#CustomTag('my-example')
class MyExample extends PolymerElement {
#observable Map<int, String> map = toObservable({'123': {'name': 'XYZ', 'size': 12}});
MyExample.created() : super.created() {
map.changes.listen((_) => notifyPropertyChange(#map, 1, 0));
}
void change() {
var object = map['123']
object['size'] = 100;
map.notifyChange(new MapChangeRecord('123', null, object));
}
}
On clicking the 'Change'-Button, the object with id '123' is updated in the map, but isn't updated in view. Has anyone an idea, how to deliver the changes to the view?
<link rel="import" href="../../packages/polymer/polymer.html">
<polymer-element name="app-element">
<template>
<div>
<ul>
<template repeat="{{ entry in map.values }}">
<li>x{{ entry['name'] }} {{ entry['size']}}</li>
<template repeat="{{ item in entry.values}}">
y{{item}}
</template>
</template>
</ul>
<button on-click="{{change}}">Change</button>
</div>
</template>
<script type="application/dart" src="app_element.dart"></script>
</polymer-element>
import 'package:polymer/polymer.dart';
#CustomTag('app-element')
class AppElement extends PolymerElement {
#observable
Map map = toObservable({'123': {'name': 'XYZ', 'size': 12}});
AppElement.created() : super.created();
void change() {
var object = map['123']['size'] = 100;
}
}

Resources