This live snippet builds a web-component which uses iron-list. Each item in the list has a delete button which, on click, removes the item from the list.
When an item is removed, all the next items shift up, but the last item displayed stays rather than disapear as it should be.
According to this stackoverflow, simply by firing the event resize on the iron-list should be enough. But in my snippet, this doesn't help. Nether the iron-resize or the notifyResize function from the official iron-list documentation.
<script src="https://polygit.org/components/webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="https://polygit.org/components/polymer/polymer-element.html">
<link rel="import" href="https://polygit.org/components/iron-list/iron-list.html">
<link rel="import" href="https://polygit.org/components/paper-button/paper-button.html">
<dom-module id="my-list">
<template>
<iron-list id="list" items="{{items}}">
<template>
<div style="display:flex; justify-content: space-between; align-items: center;">
<div style="margin: 20px; ">
{{item}}
</div>
<paper-button on-tap="_onDeleteClicked"
style="background: red; color: white;">Remove</paper-button>
</div>
</template>
</iron-list>
</template>
<script>
class MyList extends Polymer.Element {
static get is() { return "my-list"; }
// set this element's employees property
constructor() {
super();
this.items = [1,2,3,4];
}
_onDeleteClicked(event){
this.splice("items", event.model.index, 1);
// ---- any resize call doesn't help a thin ---
this.$.list.fire('iron-resize');
this.$.list.fire('resize');
this.$.list.notifyResize();
}
}
customElements.define(MyList.is, MyList);
</script>
</dom-module>
<my-list></my-list>
You may find an "hidden" attribute on the last item. As items are reused by iron-list when scrolling the item does not get removed. This CSS rule should hide it away
#list [hidden] { display: none; }
"It's simple! The css display property of the root element, in the iron-list's template, must not be set. Then just wrap your flexbox in another simple div."
Here's the live snippet solved:
<script src="https://polygit.org/components/webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="https://polygit.org/components/polymer/polymer-element.html">
<link rel="import" href="https://polygit.org/components/iron-list/iron-list.html">
<link rel="import" href="https://polygit.org/components/paper-button/paper-button.html">
<dom-module id="my-list">
<template>
<iron-list id="list" items="{{items}}">
<template>
<!--YOU MUST NO CHANGE THE CSS DISPLAY PROPERTY OF THE ROOT ELEMENT OF THE TEMPLATE!-->
<div>
<div style="display:flex; justify-content: space-between; align-items: center;">
<div style="margin: 20px; ">
{{item}}
</div>
<paper-button on-tap="_onDeleteClicked"
style="background: red; color: white;">Remove</paper-button>
</div>
</div>
</template>
</iron-list>
</template>
<script>
class MyList extends Polymer.Element {
static get is() { return "my-list"; }
// set this element's employees property
constructor() {
super();
this.items = [1,2,3,4];
}
_onDeleteClicked(event){
this.splice("items", event.model.index, 1);
this.$.list.notifyResize();
}
}
customElements.define(MyList.is, MyList);
</script>
</dom-module>
<my-list></my-list>
Related
I try implement row-datails in webcomponnet written in polymer 2. For this I use example : https://vaadin.com/components/vaadin-grid/html-examples/grid-row-details-demos#row-details-with-polymer-template
I try show row details in two ways: _onActiveItemChanged end expanded.
When I use it the lines have doubled.
How to show my template?
My code
<link rel="import" href="./bower_components/vaadin-button/vaadin-button.html" />
<link
rel="import"
href="./bower_components/vaadin-text-field/vaadin-text-field.html"
/>
<link
rel="import"
href="./bower_components/vaadin-checkbox/vaadin-checkbox-group.html"
/>
<link
rel="import"
href="./bower_components/vaadin-combo-box/vaadin-combo-box.html"
/>
<link
rel="import"
href="./bower_components/vaadin-checkbox/vaadin-checkbox.html"
/>
<link rel="import" href="./bower_components/vaadin-grid/vaadin-grid.html" />
<link
rel="import"
href="./bower_components/vaadin-grid/vaadin-grid-column.html"
/>
<link
rel="import"
href="./bower_components/paper-checkbox/paper-checkbox.html"
/>
<dom-module id="grid-wraper">
<template>
<style>
:host {
display: block;
}
.details {
padding: 10px;
margin: 10px;
display: flex;
justify-content: space-around;
align-items: center;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14);
font-size: 20px;
}
img {
width: 80px;
height: 80px;
}
</style>
<div class="card card-scale-anim">
<div class="card-titleBlue">
<iron-icon class="icon-user" icon="account-circle"></iron-icon>
<h2 class="title">Lista użytkowników e-usług</h2>
</div>
<div class="org-users-table">
<vaadin-grid
class="users-grid"
id="grid"
height-by-rows
data-provider="[[_gridDataProvider]]"
style="height: auto"
selected-items="{{_selectedItems}}"
active-item="{{_activeUser}}"
on-active-item-changed="_onActiveItemChanged"
>
<template class="row-details">
<div class="details">
<img src="[[item.picture.large]]" />
<p>Hi! My name is [[item.name]]!</p>
</div>
</template>
<vaadin-grid-column resizable width="100px">
<template>[[item.name]]</template>
</vaadin-grid-column>
<vaadin-grid-column width="100px">
<template class="header"></template>
<template>
<paper-checkbox
aria-label$="Show Details for [[item.name]]"
checked="{{expanded}}"
>Show Details</paper-checkbox
>
</template>
</vaadin-grid-column>
</vaadin-grid>
</div>
</div>
</template>
<script>
class GridWraper extends Polymer.Element {
static get is() {
return "grid-wraper";
}
static get properties() {
return {
dataProvider: { type: Function, notify: true },
};
}
_onActiveItemChanged(e) {
console.log("Active item", e);
this.$$("#grid").expandedItems = [e.detail.value];
}
$$(selector) {
return this.shadowRoot.querySelector(selector);
}
ready() {
super.ready();
Polymer.RenderStatus.afterNextRender(this, function () {});
}
}
window.customElements.define(GridWraper.is, GridWraper);
</script>
</dom-module>
If you want to expand the items on active change (ie. when user clicks on the row), then your _onActiveItemChanged method should use Grid's detailsOpenedItems property like so:
_onActiveItemChanged(e) {
this.$.grid.detailsOpenedItems = [e.detail.value];
}
However, if you want to open the detail with the checkbox, then you would need to bind the checked attribute to detailsOpened:
<paper-checkbox aria-label$="Show Details for [[item.firstName]]" checked="{{detailsOpened}}">Show Details</paper-checkbox>
A small note:
Polymer components bind all elements with id to a $ object, so instead of this.$$("#grid"), you can use this.$.grid (as seen on my code above).
I ran into a problem with polymer and app-storage when trying to remove an entry.
I'm trying to add a button to the Vaading Grid that will delete the entry on which the button is set.
The only thing is that I cannot seem to make it work, when I click the button, even console.log doesn't work. What am I doing wrong here?
Here is the code:
<!--
#license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="shared-styles.html">
<link rel="import" href="../bower_components/vaadin-grid/vaadin-grid.html">
<link rel="import" href="../bower_components/vaadin-date-picker/vaadin-date-picker.html">
<link rel="import" href="../bower_components/paper-input/paper-input.html">
<link rel="import" href="../bower_components/paper-button/paper-button.html">
<link rel="import" href="../bower_components/app-storage/app-localstorage/app-localstorage-document.html">
<dom-module id="my-view1">
<template>
<style include="shared-styles">
:host {
display: block;
padding: 10px;
}
.form {
display: flex;
flex-direction: column;
}
.form paper-input {
flex: 1;
margin-right: 10px;
}
.form vaadin-date-picker {
flex: 1;
margin-top: 10px;
}
.form paper-button {
margin-top: 10px;
align-self: flex-end;
}
</style>
<div class="card">
<div class="form">
<paper-input label="Sum" value="{{todo.task}}" auto-validate placeholder="Suma" required=true pattern="[0-9]*" error-message="Numbers only"></paper-input>
<vaadin-date-picker label="When" value="{{todo.due}}"></vaadin-date-picker>
<paper-button raised on-tap="_addToDo">Add</paper-button>
</div>
<br>
<vaadin-grid items={{todos}}>
<vaadin-grid-column width="calc(50% - 100px)">
<template class="header">Sum</template>
<template>{{item.task}}</template>
</vaadin-grid-column>
<vaadin-grid-column width="calc(50% - 100px)">
<template class="header">When</template>
<template>{{item.due}}</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template>
<div style="display: flex; justify-content: flex-end;">
<button on-tap="_remove">Remove</button>
</div>
</template>
</vaadin-grid-column>
</vaadin-grid>
</div>
<app-localstorage-document key="todos" data="{{todos}}">
</app-localstorage-document>
</template>
<script>
class MyView1 extends Polymer.Element {
static get is() { return 'my-view1'; }
static get properties() {
return {
todo: {
type: Object,
value: () => { return {} }
},
todos: {
type: Array,
value: () => []
}
};
}
_addToDo() {
this.push('todos', this.todo);
this.todo = {};
};
_remove() {
console.log("Clicked!");
};
}
window.customElements.define(MyView1.is, MyView1);
</script>
</dom-module>
So the _addToDo button is working, but not the _remove button. When I open the console, this is empty.
Please let me know what am I doing wrong here. Thank you!
Since button is native HTML Element on-tap will not work.
Change it to polymer element like paper-button or change on-tap to onclick.
I am trying to implement a paper-dialog box that will reveal itself when a paper-fab is tapped in the image below:
my app's main screen
but I can't get the paper-dialog to open.
I have implemented paper-dialog into my app as following:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/polymerfire/firebase-query.html">
<link rel="import" href="../bower_components/paper-fab/paper-fab.html">
<link rel="import" href="../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../bower_components/polymerfire/firebase-auth.html">
<link rel="import" href="shared-styles.html">
<dom-module id="my-view1">
<template>
<style include="shared-styles">
:host {
display: block;
padding: 10px;
}
paper-fab{
position:fixed;
right:20px;
bottom:68px;
--paper-fab-keyboard-focus-background:--accent-color;
}
</style>
<firebase-auth
id="auth"
user="{{user}}"
provider=""
status-known="{{statusKnown}}"
on-error="handleError">
</firebase-auth>
<firebase-query
id="query"
path="/posts"
data="{{posts}}">
</firebase-query>
<div class="card">
<h1>Post</h1>
<ul id="post-list">
<template is="dom-repeat" items="[[posts]]" as="post">
<li>
<p class="content">[[post.body]]</p>
</li>
</template>
</ul>
</div>
<paper-fab icon="add" onclick="dialog.open()"></paper-fab>
<paper-dialog id="dialog">
<paper-textarea id="post" label="Write your post here..."></paper-textarea>
<paper-button dialog-dismiss>Cancel</paper-button>
<paper-button on-tap="post" id="btnPost" raised class="indigo" hidden$="[[!user]]">Post</paper-button>
</paper-dialog>
</template>
<script>
Polymer({
is: 'my-view1',
properties:{
user:{
type: Object
},
statusKnown:{
type: Object
},
posts: {
type: Object
}
},
post: function() {
this.$.query.ref.push({
"Uid": this.user.uid,
"body": this.$.post.value
});
this.$.post.value = null;
}
});
</script>
</dom-module>
<paper-fab icon="add" onclick="dialog.open()"></paper-fab>
<paper-dialog id="dialog">
<paper-textarea id="post" label="Write your post here..."></paper-textarea>
<paper-button dialog-dismiss>Cancel</paper-button>
<paper-button on-tap="post" id="btnPost" raised class="indigo" hidden$="[[!user]]">Post</paper-button>
</paper-dialog>
This snippet here are taken from the demo on this page:
https://www.webcomponents.org/element/PolymerElements/paper-dialog/v1.1.0/demo/demo/index.html
but when I actually tap on the paper-fab, I get the following error:
Uncaught ReferenceError: dialog is not defined
at HTMLElement.onclick (view3:1)
onclick # view3:1
Does anyone have any idea how I can make the paper-dialog open when the paper-fab is tapped? I suppose I am missing some includes, but I cannot figure out which one.
at first, don't use onclick. There are Polymer event attributes like on-click or on-tap. Second, you should call function which will open the selected dialog
Example:
<paper-fab icon="add" on-tap="_openDialog"></paper-fab>
and inside script
_openDialog: function() {
this.$.dialog.open();
}
this.$.dialog find element with id dialog and call function open
Can someone please help how to make this template show if the filter is not found in the array.
<template is="dom-if" if="{{itemsEmpty}}">
The array is empty!
</template>
here is my entire code. but for some reasons the if condition in the dom-if template is not working
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src='bower_components/webcomponentsjs/webcomponents-lite.min.js'></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/iron-image/iron-image.html">
<!--<link rel="import" href="bower_components/iron-ajax/iron-ajax.html">-->
<link rel="import" href="bower_components/paper-item/paper-item.html">
<link rel="import" href="bower_components/paper-input/paper-input.html">
<link rel="import" href="bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="bower_components/paper-listbox/paper-listbox.html">
<link rel="import" href="bower_components/paper-button/paper-button.html">
<style>
.taller{
height:120px;
}
[vertical-align="top"] ul {
margin-top: 0;
}
[vertical-align="bottom"] ul {
margin-bottom: 0;
}
button, paper-button {
border: 1px solid #ccc;
background-color: #eee;
/*padding: 1em;*/
border-radius: 3px;
cursor: pointer;
}
button:focus {
outline: none;
border-color: blue;
}
</style>
</head>
<body>
<dom-module id="employee-list">
<template>
<paper-input value="{{filterValue}}" label="Search For a Company" floatingLabel id="searchCompany"></paper-input>
<paper-dropdown-menu label="Select Project Type">
<paper-listbox class="dropdown-content" >
<template is="dom-repeat" items="{{items}}" as="test" filter="{{Filter(filterValue:input)}}">
<paper-item value="{{test.fname}}">{{test.fname}} - {{test.lname}}</paper-item>
</template>
</paper-listbox>
</paper-dropdown-menu>
<paper-listbox >
<template is="dom-repeat" items="{{items}}" filter="{{Filter(filterValue)}}">
<div class="row">
<div class="col-sm-12" style="font-size:15px;font-family:'Open Sans'">
{{item.fname}} - {{item.lname}}
</div>
<hr />
<template is="dom-if" if="{{itemsEmpty}}">
The array is empty!
</template>
</div>
</template>
</paper-listbox>
</template>
<script>
Polymer({
is: 'employee-list',
properties: {
items: {
type: Array,
observer: '_itemsChanged'
},
filterValue: {
type: String,
notify:true
},
itemsEmpty: {
type: Boolean
}
},
ready: function() {
this.items = [{'fname': 'Jack', 'lname':'Bayo'}, {'fname': 'Skellington','lname':'Dar' }];
},
_itemsChanged: function(items){
this.itemsEmpty = items.length == 0;
},
Filter: function (val) {
return function (items) {
if (!items) return false;
if (val != null || val != undefined) {
return (items.fname && ~items.fname.toLowerCase().indexOf(val.toLowerCase())) ||
(items.lname && ~items.lname.toLowerCase().indexOf(val.toLowerCase()));
}
else
return true;
};
}
});
</script>
</dom-module>
<employee-list></employee-list>
</body>
</html>
I will really appreciate any help here. Here is the plunker: http://plnkr.co/edit/Qy6LeAfe93u4CK2G43eX?p=preview
Thank you
I've found a number of problems with your sample:
The polymer.html import breaks your plunk (see all the errors from registerElement). That's because the other imports try to import Polymer from different URLs
The dom-if is inside the dom-repeat
Observing items won't work because the items property isn't changed when you use filter.
What does change is renderedItemCount property, which you can observe and use to control the dom-if. The property is updated whenever filter fires or items array changes.
To sum up:
Remove Polymer import
Move dom-if outside repeater
Add binding to dom-repeat: rendered-item-count="{{renderedCount}}"
Change the if property to use the actually rendered item count: if="{{!renderedCount}}"
Here's how the element's template can look:
<paper-input value="{{filterValue}}" label="Search For a Company" floatingLabel id="searchCompany"></paper-input>
<paper-listbox >
<template is="dom-repeat" items="{{items}}" filter="{{Filter(filterValue)}}" rendered-item-count="{{renderedCount}}">
<div class="row">
<div class="col-sm-12" style="font-size:15px;font-family:'Open Sans'">
{{item.fname}} - {{item.lname}}
</div>
<hr />
</div>
</template>
<template is="dom-if" if="{{!renderedCount}}">
The array is empty!
</template>
</paper-listbox>
This is untested, but I think.
<template is="dom-if" if="{{!items}}">
should be
<template is="dom-if" if="{{itemsEmpty}}">
My code with swipable-container and dom-repeat of firebase-data
<iron-swipeable-container id="teamchat">
<paper-card class="swipe item blue">
<template is="dom-repeat" items="[[tcmmessages]]" as="tcmmessage">
<div class="card-content">
<b>[[tcmmessage.teamname]]</b><br>
[[tcmmessage.beitrag]]<br>
<span class="chatmetadata">von [[tcmmessage.username]]
• [[tcmmessage.update]] • [[tcmmessage.uptime]] </span>
</div>
</template>
</paper-card>
</iron-swipeable-container>
I have defined a listener
listeners: {
'teamchat.iron-swipe': '_onTeamChatSwipe'
},
and remove the firebase-data with '_onTeamChatSwipe'.
That work fine!
But when there is new firebase-data, how can I bring the iron-swipeable-container back again without refreshing the entire page? I don't find a solution.
It looks like you've created just one paper-card that contains multiple messages. When the card is swiped away, your code has no template to refill the container.
Did you actually mean to create a card for each message? That would require moving paper-card inside the template repeater like this:
<iron-swipeable-container id="teamchat">
<template is="dom-repeat" items="[[tcmmessages]]" as="tcmmessage">
<paper-card class="swipe item blue">
<div class="card-content">
<b>[[tcmmessage.teamname]]</b><br>
[[tcmmessage.beitrag]]<br>
<span class="chatmetadata">von [[tcmmessage.username]]
• [[tcmmessage.update]] • [[tcmmessage.uptime]] </span>
</div>
</paper-card>
</template>
</iron-swipeable-container>
When tcmmessages refills (via Firebase), the iron-swipeable-container automatically repopulates with a paper-card per message.
Here's a demo of similar code that shows that behavior:
<head>
<base href="https://polygit.org/polymer+1.4.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="paper-card/paper-card.html">
<link rel="import" href="iron-swipeable-container/iron-swipeable-container.html">
<link rel="import" href="iron-flex-layout/iron-flex-layout-classes.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<style include="iron-flex">
paper-card {
margin-bottom: 16px;
}
</style>
<template>
<iron-swipeable-container class="container">
<template is="dom-repeat" items="[[items]]">
<paper-card heading="{{item}}" class="layout vertical">
<div class="card-content">
Swipe me left or right
</div>
</paper-card>
</template>
</iron-swipeable-container>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-foo',
properties : {
items: {
type: Array,
value: function() {
return [1,2,3];
}
}
},
_clearListAfterDelay: function(delay) {
this.async(function() {
this.set('items', []);
}, delay);
},
_refillListAfterDelay: function(delay) {
this.async(function() {
this.push('items', 4);
this.push('items', 5);
}, delay);
},
ready: function() {
this._clearListAfterDelay(1000);
this._refillListAfterDelay(2000);
}
});
});
</script>
</dom-module>
</body>
codepen