Polymer paper menu button - polymer

I am very new to web development and am attempting to learn to use polymer to create a simple webpage. I have created a drop down menu populated by the names in a json file similar to the below example. I cannot understand how to display the data associated with the selected menu item. below is the demo code from the polymer project. I understand this question may seem very simple to some of you. Thank you in advance for your patience and any assistance that may be provided.
<paper-menu-button>
<paper-icon-button icon="menu" noink></paper-icon-button>
<paper-dropdown class="dropdown">
<core-menu class="menu">
<template repeat="{{name in food}}">
<paper-item>{{}}</paper-item>
</template>
</core-menu>
</paper-dropdown>
</paper-menu-button>

there are several ways you can check a menu for user input.
method 1
you can use a EventListener to look for the core-select event. to do that you would give the core-menu a id. i am calling it select.
that would make the function look like
this.$.select.addEventListener('core-select', function () {
// access the value with this.selected
});
method 2
you could also use the declarative approach also using a EventListener but this time as a attribute on-core-select="{{selectAction}}" then the function would look like.
selectAction: function () {
// value would be this.$.select.selected if using the select id on the core-menu
}
method 3
you could also use a attribute changed function to get the value when changed. that method would look like.
<paper-menu-button>
<paper-icon-button icon="menu" noink></paper-icon-button>
<paper-dropdown class="dropdown">
<core-menu class="menu" selected="{{selected}}">
<template repeat="{{name in food}}">
<paper-item>{{}}</paper-item>
</template>
</core-menu>
</paper-dropdown>
</paper-menu-button>
the change would call a function that would look something like
selectedChanged: function () {
// value would be this.selected
}
i also made a plunker showing all 3 in use check console for output when selecting http://plnkr.co/edit/odQwNRLFTzyATodQUNh0?p=preview
edit: all this is assuming you are working inside a custom element. outside a custom element method 1 would still work. method 2 and 3 would require a auto-binding template

I'm very new to Polymer too, but I got tabs working this way (i think it may apply to drop-down too):
In normal web-pages:
<body>
<template is="dom-bind" id="app">
<div class="container">
<div class="menu-area">
<paper-tabs selected="{{selected}}" on-iron-select="_onTabSelected">
<template is="dom-repeat" items="[[items]]">
<paper-tab>[[item.name]]</paper-tab>
</template>
</paper-tabs>
</div>
</div>
</template>
<script>
app._onTabSelected = function (e) {
var selectedIndex = e.srcElement.selected;
var item = this.items[selectedIndex];
document.location = item.uri;
};
app.items = [
{id: 'HOME', name: 'Home', uri: "home.html"},
{id: 'PRODUCTS', name: 'Products', uri: "products.html"},
{id: 'USERS', name: 'Users', uri: "users.html"}
];
</script>
</body>
</html>
When composing new elements:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-tabs/paper-tabs.html">
<link rel="import" href="../../bower_components/paper-tabs/paper-tab.html">
<dom-module id="app-header-menu">
<template>
<div class="container">
<div class="menu-area">
<paper-tabs selected="{{selected}}" on-iron-select="_onTabSelected">
<template is="dom-repeat" items="[[items]]"><paper-tab>[[item.name]]</paper-tab></template>
</paper-tabs>
</div>
</div>
</template>
<script>
Polymer({
is: "app-header-menu",
properties: {
items: {
type: Array,
notify: false,
readOnly: false,
value: [
{id: 'HOME', name: 'Home', uri: "home.html"},
{id: 'PRODUCTS', name: 'Products', uri: "products.html"},
{id: 'USERS', name: 'Users', uri: "users.html"}
]
}
},
_onTabSelected: function (e) {
var selectedIndex = e.srcElement.selected;
var item = this.items[selectedIndex];
document.location = item.uri;
}
});
</script>
</dom-module>

Related

How to rerender the complete dom-repeat in Polymer on a Array change

I just started playing with Polymer and have been struggling to solve following issue.
In below code when the button is clicked myItem array is changed and parent template dom-repeat is rerendered, but the child template dom-repeat is not updated.
The reason might be the child dom-repeat is bound to the function _get.
<dom-module id="my-element">
<template>
<button on-click="_removeLastTwo">switch</button>
<template is="dom-repeat" items="{{myItem}}">
<ul>
<template is="dom-repeat" items="{{_get(item)}}">
<li>{{item}}</li>
</template>
</ul>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'my-element',
properties: {
data: {
type: Array,
value: [9,8]
},
myItem:{
type:Array,
value:[1,2,3,4,5]
}
},
_get:function(t){
var d = this.myItem.length;
return [d+1,d+2]
},
_removeLastTwo: function(){
this.myItem = [1,2]
}
});
</script>
How can I overcome this issue, check it at http://jsbin.com/misuvehuwe/edit?html,output . Am I missing any basic approach??

app-indexeddb-mirror with Polymerfire

I built a simple page that has multiple tabs. Each tab loads a feed (collection/list) of articles from Firebase and renders cards on the page. Everything works as I wanted until I tried to persist the visited feeds into indexeddb with app-indexeddb-mirror.
Here's what I did:
<dom-module id="my-view1">
<template>
<style include="shared-styles">
</style>
<paper-tabs id="tabs"
attr-for-selected="value"
selected="{{selectedFeed}}"
scrollable>
<template is="dom-repeat"
items="[[feeds]]"
as="feed">
<paper-tab value="[[feed.key]]">[[feed.name]]</paper-tab>
</template>
</paper-tabs>
<firebase-query id="[[selectedFeed]]_feed"
app-name="myfirebaseapp"
path="/myfirebaseappdb/feed/[[selectedFeed]]"
data="{{articles}}">
</firebase-query>
<app-indexeddb-mirror
key="[[selectedFeed]]"
data="[[articles]]"
persisted-data="{{persistedArticles}}">
</app-indexeddb-mirror>
<template is="dom-repeat"
items="[[persistedArticles]]"
as="article">
<paper-card image="[[article.image]]" alt="image">
<div class="card-content">
<h1 class="card-text">[[article.title]]</h1>
<h4 class="card-text">[[article.abstract]]</h4>
</div>
</paper-card>
</template>
</template>
<script>
Polymer({
is: 'my-view1',
ready: function () {
this.feeds = [
{name: "Feed1", key: "feed1"},
{name: "Feed2", key: "feed2"},
{name: "Feed3", key: "feed3"},
{name: "Feed4", key: "feed4"}
];
}
});
</script>
What I want to do is cache each feed into indexeddb as an entry (feed name as key and the data as value), so they can be loaded when the app is offline. That's basically what app-indexeddb-mirror is for, right?
However I cannot get my head around the data flow between firebase-query and app-indexeddb-mirror, and I keep getting indexeddb entry overwritten/emptied when switching tabs.
Is there something I am not doing right? Thanks.
I solved this issue by swapping firebase-query and app-indexeddb-mirror.
I never knew sequence matters in Polymer, also this order is quite counter-intuitive.

Polymer 1.0 dom-repeat fails "Uncaught TypeError: Cannot read property 'extends' of undefined"

I have a simple dom-module with an dom-repeat template in it:
<dom-module id="bookmark-extends">
<style>(...)</style>
<template>
<template is="dom-repeat" items="[[extends]]" as="extend">
<a href="[[extend.url]]">
<paper-button>[[extend.__firebaseKey__]]</paper-button>
</a>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'bookmark-extends',
properties: {
extends: {
type: Array,
notify: true,
value: function(){ return []; }
}
}
});
</script>
Here where I use it:
<dom-module id="bookmark-cards">
<style>(...)</style>
<template>
<firebase-collection
location="*******"
data="{{bookmarks}}"></firebase-collection>
<template is="dom-repeat" items="[[bookmarks]]" as="bookmark">
(...)
<div hidden="[[!bookmark.extendable]]" class="card-actions">
<bookmark-extends extends="[[bookmark.extends]]">
</bookmark-extends>
</div>
<div hidden="[[!bookmark.searchable]]" class="card-actions">
<input-search-on-site id="input" website-name="[[bookmark.__firebaseKey__]]" website-search-url="[[bookmark.searchUrl]]">
</input-search-on-site>
</div>
</paper-card>
</template>
</template>
</dom-module>
<script>Polymer({
is: 'bookmark-cards'
});</script>
I'm getting this error:
Uncaught TypeError: Cannot read property 'extends' of undefined
Please help me, I don't know what to do,
because in my second code the nearly same process is working...
EDIT:
Now I don't use an extra module and don't use the word "extend" anymore...
<div hidden="[[!bookmark.expandable]" class="card-actions">
<template is="dom-repeat" items="[[bookmark.links]]" as="link">
<paper-button>{{link.__firebaseKey__}}</paper-button>
</template>
</div>
The new Error is: "[dom-repeat::dom-repeat]: expected array for items, found Object"
If I try this:
properties: {
links: {
type: Array,
notify: true,
value: function(){ return []; }
}
}
The same error comes.
Couple of things. Move your script element inside the dom-module tag, as per Polymer recommendations.
https://www.polymer-project.org/1.0/docs/devguide/properties.html
Secondly don't use "extends" as an instance variable/property name. Extends is a Polymer keyword for extending existing HTML elements.
https://www.polymer-project.org/1.0/docs/devguide/registering-elements.html
This Plunker shows the key changes: http://plnkr.co/edit/BKzrfC
<dom-module id="bookmark-extends">
<template>
<template is="dom-repeat" items="[[extnds]]" as="extend">
<div>extend</div>
</template>
</template>
<script>
Polymer({
is: 'bookmark-extends',
properties: {
extnds: {
type: Array,
notify: true,
value: function(){ return ['one', 'two']; }
}
}
});
</script>
</dom-module>

Tap listener for polymer iron-list item?

I have a custom element that utilizes iron-list to display an array of objects. Each item is generated via a template as follows:
<iron-list id="projectList" items="[[projects]]" indexAs="_id" as="projLI" class="layout flex">
<template>
<div>
<paper-material id="itemShadow" animated elevation="1">
<div class="item layout horizontal" onmouseover="hoverOver(this)" onmouseout="hoverOut(this)">
<!-- I use a paper-menu-button to display a list of available actions here -->
<!-- list item object content here such as: [[projLI.desc]] etc. -->
</div>
</paper-material>
</div>
</template>
</iron-list>
What is the best polymer-friendly approach to detect both a tap event on the iron-list item itself (ideally knowing which item was actually tapped via projLI._id), yet also be able to handle the internal paper-menu-button tap events in a different way?
I've eye-balled polymer 1.0's new event listeners (https://www.polymer-project.org/1.0/docs/devguide/events.html), as a possible approach, attempting to listen for different element tap events (as shown in example 1 on that page), but I'm not sure if that will work here. I've also considered possibly using iron-selector somehow around iron-list? Is that doable? I'm not sure that will work either, given that iron-selector would only have one child (i.e. the iron-list element and not it's templated children).
I feel like I'm missing a really easy way to accomplish this. Can someone please show me the light?
Follow the model outlined on lines 154 and 184 of this demo.
https://github.com/PolymerElements/iron-list/blob/master/demo/collapse.html
my-element.html
<iron-list items="[[items]]">
<template>
<my-list-item on-tap="_toggleMe"></my-list-item>
</template>
</iron-list>
...
_toggleMe: function(e) {
console.log(e.model.index);
}
The key is to place the event and listener method (toggleMe() in this case) inside the <template> of the iron-list. This allows the iron-list to register the array index.
I do this by encoding an array index in a list element id, then pulling the id out of a list item event target. Here is an example Polymer element that does this.
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-list/iron-list.html">
<dom-module id="list-example">
<style>
:host {
display: block;
}
#list-example {
height: 100px;
}
</style>
<template>
<paper-material animated elevation="1">
<iron-list id="list-example" items="[[data]]">
<template>
<div id="{{index2id(item.index)}}" on-mouseover="onMouseOverItem">{{item.name}}</div>
</template>
</iron-list>
</paper-material>
</template>
</dom-module>
<script>
(function () {
Polymer({
is: 'list-example',
ready: function() {
for(var i = 0; i < this.data.length; i++) {
this.data[i].index = i;
}
},
index2id: function(index) {
return "_" + index;
},
id2index: function(id) {
return Number(id.substr(1));
},
onMouseOverItem: function(e) {
console.log('on-mouseover list item:', this.data[this.id2index(e.target.getAttribute('id'))]);
},
properties: {
data: {
type: Array,
value: [{name: 'A'}, {name: 'B'}, {name: 'C'},
{name: 'D'}, {name: 'E'}, {name: 'F'},
{name: 'G'}, {name: 'H'}, {name: 'I'}]
}
}
});
})();
</script>
I was having a similar issue and solved my problem using <array-selector> as follows:
<iron-list items="{{myarray}}" as="ref">
<template>
<div>
<paper-checkbox on-tap="toggleSelection"></paper-checkbox>
<span>{{ref.name}}</span>
</div>
</template>
</iron-list>
<array-selector id="arrsel" items="{{myarray}}"
selected="{{selectedName}}" toggle></array-selector>
and myarray is an array of objects:
var myarray = [{name: "Alice"}, {name: "Ben"}, ...]
and the function toggleSelection is defined as follows:
toggleSelection: function(e) {
console.log ("Selected index is " + e.model.index);
console.log ("Selected name is " + e.model.ref);
this.$.arrsel.select (e.model.ref);
console.log ("Current selection: ", this.selectedName);
}
The field name ref after e.model.__ is the value of the as attribute of iron-list.
WARNING: The variable e.model is not officially documented on the Polymer 1.0 iron-list doc (https://elements.polymer-project.org/elements/iron-list), however I discovered it during my debugging session. I am assuming that e.model is a public property (the coding style of Polymer uses underscore prefix for private property such as: _scroll_Position) and it is not a candidate for deprecation.
I just solved my issue of here https://groups.google.com/forum/#!topic/polymer-dev/r9IsUKVnLVM. Reading this documentation https://www.polymer-project.org/1.0/docs/devguide/events.html.
I hope it helps you!
Wrap your iron-list with an iron-selector - this allows you get to get the row selected / tapped.
(NB: you might need to remove your custom indexAs="_id" attribute to get the right row index)
<iron-selector attr-for-selected="index" on-tap="_itemSelected">
<iron-list id="projectList" items="[[projects]]" as="projLI" class="fit">
<template>
<div class="layout horizontal center" id="{{index}}">
<!-- your row content here -->
</div>
</template>
</iron-list>
</iron-selector>
Polymer method for row item selected:
_itemSelected: function (e) {
console.log(e.target.id); // selected iron-list row index
}

Polymer 1.0 - How to bind html value

I have a list of items in which each item has a .content html value as following.
<template is="dom-repeat" items="{{entries}}">
<li><p class="paper-font-body2">{{item.title}}</p>
<div>{{item.content}}</div></li>
</template>
content field is somewhat like this
Hello <strong>Polymer</strong>
It shows in browser as plain text. How do I show it as safe html?
EDIT: this issue is raised, but it doesn't help me.
You could easily do:
<template is="dom-repeat" items="{{entries}}">
<li><p class="paper-font-body2">{{item.title}}</p>
<div inner-h-t-m-l="{{item.content}}"></div></li>
</template>
That's what I'm using, bearing in mind that XSS vulnerability is open.
You could try something like this:
<dom-module id="echo-html">
<template>
<span>{{html}}</span>
</template>
<script>
Polymer({
is: 'echo-html',
properties: {
html: {
type: String,
value: 'html'
}
},
ready: function() {
this.innerHTML = this.html;
}
});
</script>
</dom-module>
and call it like that I guess:
<div><echo-html html="{{item.content}}"></echo-html></div>