populate content based on list selection in Polymer - polymer

I'm trying to use the application layout "nav-list-detail" in Polymer but not sure how to select something from
<!-- List -->
<paper-menu class="list" on-iron-activate="_listTap">
<template is="dom-repeat" items="{{items}}">
<paper-item><span class="paper-font-body1">{{item}}</span></paper-item>
</template>
</paper-menu>
and have it populate
<!-- Main Content -->
<div class="content"></div>
My model is
<script>
(function() {
Polymer({
is: 'nav-list-detail',
_computeListWidth: function(isMobile) {
// when in mobile screen size, make the list be 100% width to cover the whole screen
return isMobile ? '100%' : '33%';
},
_listTap: function() {
this.$.mainDrawerPanel.closeDrawer();
},
properties: {
items: {
type: Array,
notify: true,
}
},
ready: function() {
this.items = [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5'
]
}
});
})();
</script>
I'm pretty new with Polymer (especially 1.0) so it may be a simple solution that I'm just missing.

If you have a side menu like that ( notice on-click="menuSelected" ):
<dom-module id="dmf-menu">
<template>
<paper-menu>
<template is="dom-repeat" items="{{modules}}">
<paper-item on-tap="menuSelected">{{item.name}}</paper-item>
</template>
</paper-menu>
</template>
You can add on-tap on paper-item to execute menuSelected method.
And then you can use e.model.item to access your clicked item model.
<script>
(function() {
Polymer({
is: 'nav-list-detail',
menuSelected: function (e) {
console.log(e.model.item);
}
});
})();
</script>
If you have your items array be an array of objects, you will get your selected object.
From here you can populate it easily to your <div class="content">

Use the selected property of the paper-menu:
<paper-menu class="list" selected={{selectedItem}} >
This adds the iron-selected class to the selected paper-item. I am not sure what you mean by "populate the main content". Just put your menu inside the main template tag of your dom-module.
For an initial list you can add the value to your properties:
properties: {
items: {
type: Array,
value: [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5'
],
notify: true
}
},

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??

Polymer Iron list display is incorrect

<dom-module id="page-list">
<style include="shared-styles"></style>
<style>
iron-list {
height: 500px;
}
</style>
<template>
<neon-animated-pages id="pages" selected="0">
<neon-animatable><paper-button id="list-button" raised on-tap="_onOK" >List</paper-button></neon-animatable>
<neon-animatable>
<iron-list id="list" items="[[data]]" as="item">
<template>
<div>
Name: <span>[[item.name]]</span>
</div>
</template>
</iron-list>
</neon-animatable>
</neon-animated-pages>
</template>
<script>
Polymer({
is: "page-list",
attached: function () {
this.data=[
{
index: 0,
name: "Liz Grimes"
},
{
index: 1,
name: "Frazier Lara"
},
{
index: 2,
name: "Dora Griffith"
}];
this.$.list.fire('resize');
},
behaviors: [
Polymer.NeonAnimatableBehavior
],
properties: {
data: {
type: Array,
notify: true
}
},
_onOK: function (e) {
this.$.pages.selected="1";
}
});
</script>
After pushing the "List" button, the iron list is expected to be totatlly displayed. Unfortunately, the result is a display of one line with "Name:" and nothing else. If I force the selected page to "1", <neon-animated-pages id="pages" selected="1"> which means that on the first resfresh of the browser, the page with the iron list is displayed, the display is correct : three lines with the correct data.
The issue seems to be related to the fact that on startup, the page with the iron list is not yet displayed.
Anybody knows how to solve this ?
Seems to be a known issue https://github.com/PolymerElements/neon-animation/issues/115
Please check my suggested solution on github.
I think you need
this.set('data', [...]);
instead of
this.data=[...];
for Polymer to get notice of data change
The following solution is merely a hack, but if you listen to the iron-resize event on your neon-animatable and then call notifyResize() on any child iron-list elements you should be able to get around this issue until a more sustainable fix can be made to https://github.com/PolymerElements/neon-animation/issues/115

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
}

dom-repeat template fails to render array with error 'expected array for items'

I have a simple template that renders an array object. However, it fails with the following message:
[dom-repeat::dom-repeat]: expected array for `items`, found [{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]
The array is passed in the attribute of the custom element in the following format:
[{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]
I have read the docs on template repeaters several times and still unable to find what I am doing wrong.
Any help would be much appreciated!
Here is my custom element:
<dom-module id="x-myelement">
<template>
<div>
<h1>{{title}}</h1>
<ul>
<template is="dom-repeat" as="menuitem" items="{{items}}">
<li><span>{{menuitem.code}}</span></li>
</template>
</ul>
</div>
</template>
<script>
(function() {
Polymer({
is: 'x-myelement',
title: String,
items: {
type: Array,
notify: true,
value: function(){ return []; }
}
});
})();
</script>
</dom-module>
And here is now I use it:
<x-myelement title="Hello Polymer"
items='[{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]'>
</x-myelement>
You need to put your element properties into the properties object (see the Polymer documentation on properties):
Polymer({
is: 'x-myelement',
properties: {
title: String,
items: {
type: Array,
notify: true,
value: function() {return [];}
}
}
});
Otherwise Polymer has no information about your properties. It treated items as a string and didn't parse the attribute value as a JSON array. Eventually dom-repeat was passed a string for its items property as well, resulting in the error that you saw.

Polymer paper menu button

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>