I'm trying to bind some data in a custom element but to no avail. I have a system-menu.html that has my custom element:
system-menu.html
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-menu-behavior/iron-menubar-behavior.html">
<dom-module id="system-menu">
<template>
<template is="dom-repeat" items="{{data}}">
<li>{{item.name}}</li>
</template>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'system-menu',
behaviors: [
Polymer.IronMenubarBehavior
],
ready: function() {
console.log(this.data);
}
});
})();
</script>
This is how I use it (Note that i've done all imports for the other items)
<link rel="import" href="/themes/_components/custom_components/system-menu/system-menu.html">
<style>
.list {
display: inline-block;
padding: 8px 0;
}
.list li {
display: block;
padding: 8px;
}
.list li[disabled] {
color: #ccc;
}
</style>
<system-menu class="list flex horizontal end-justified layout" data="{{data}}"></system-menu>
Also, {{data}} in this file is json encoded data from php. Here it is
{"login":{"url":"/login","parent_id":"0"},"register":{"url":"/register","parent_id":"0"}}
My question is, how am I supposed to access and use this json data data in my system-menu.html module?
Currently i'm getting these error:
[dom-repeat::dom-repeat]: expected array for items, found
{
Uncaught TypeError: Cannot read property 'getKey' of undefined
First, you need to transform your json {{data}} into an array of objects readable by <template is='dom-repeat'>. I assume that you want
{"login":{"url":"/login","parent_id":"0"},"register":{"url":"/register","parent_id":"0"}}
to become something like
[ {name: "login", url: "/login", parent_id: "0"}, {name: "register", url: "/register", parent_id: "0"} ]
The actual code to do the above should be trivial and beyond the scope of this question.
Second, you need to publish the data property in your <system-menu> custom element since you are binding the data attribute from the parent template.
<system-menu class="list flex horizontal end-justified layout" data="{{data}}"></system-menu>
You can pass in a computed function (to perform the conversion from your json {{data}} into the dom-repeat-compatible array) into the items attribute in the <template is='dom-repeat'> tag.
Putting it all together, your system-menu.html might look something like that
<dom-module id="system-menu">
<template>
<template is="dom-repeat" items="{{_transformData(data)}}">
<li>{{item.name}}</li>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'system-menu',
behaviors: [
Polymer.IronMenubarBehavior
],
properties: {
data: Object
},
_transformData: function (d) {
// place transformation code here
return transformedDataThatIsNowAnArray;
},
ready: function() {
console.log(this.data);
}
});
</script>
Related
I ran into a problem when trying to update the value of an array inside my .
I've been searching on google since last 4 hours, but no luck
I have the follwing 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="Date" value="{{todo.due}}"></vaadin-date-picker>
<paper-button raised on-tap="_addToDo">Add</paper-button>
</div>
<br>
<vaadin-grid id="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">Date</template>
<template>{{item.due}}</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template>
<div style="display: flex; justify-content: flex-end;">
<paper-button raised on-tap="_remove">remove</paper-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(e) {
var index = this.todos.indexOf(e.model.item);
this.todos.splice(index, 1);
this.$.grid.clearCache();
};
}
window.customElements.define(MyView1.is, MyView1);
</script>
</dom-module>
I'm trying to update localStorage after removing one of the items.
I have no idea how to "commit the update". Is there any way to update the localStorage after removing the item? Thanks!
If you manipulate an array using the native methods (like Array.prototype.splice), you must notify Polymer after the fact.
So, you can notify using notifySplices. More about notifySplices.
OR, use the Polymer methods for array mutations.
Every Polymer element has the following array mutation methods available:
push(path, item1, [..., itemN])
pop(path)
unshift(path, item1, [...,
itemN])
shift(path)
splice(path, index, removeCount, [item1, ..., itemN])
You are not required to notify if you are using Polymer array mutation method.
So, use this.splice('todos', index, 1) instead of this.todos.splice(index, 1);, this will notify changes made in the array todos which will reflect changes in the localstorage as well.
I'm working on a Polymer application that uses iron-form to submit a form to a back-end web-service. One of the elements in the form is a box where the user can select multiple elements.
Using the paper-dropdown-menu with a paper-listbox with multi set works, but the UX is horrible because the user can't see which elements are selected without opening the dropdown (and blocking other elements). Also - it requires more clicks to operate.
Ideally we'd just use the paper-listbox without the paper-dropdown-menu, as that is exactly the UI that we need - similar to HTML's classic <select multiple> but with a Material Design sheen. But without the paper-dropdown-menu wrapper, iron-form doesn't pick up on the paper-listbox selected values and will not submit those.
I've noticed that iron-form support classic HTML <select> (and even support the multiple behavior), but the UI for that is jarring in contrast with the rest of the form.
Is there something else that we can wrap around the paper-listbox to get the form to behave without modifying the original paper-listbox UI, or get paper-dropdown-menu to have an "always open" mode? If neither of those work (and I couldn't get either to work, BTW), what else can we do?
You could wrap the <paper-listbox> in a custom element that implements <iron-form-element-behavior>. The behavior exposes a value property, which could be bound to <paper-listbox>.selectedValues, allowing <iron-form> to submit the multiple listbox values:
<dom-module id="multi-listbox">
<template>
<paper-listbox multi selected-values="{{value}}">
<content></content>
</paper-listbox>
</template>
<script>
Polymer({
is: 'multi-listbox',
behaviors: [Polymer.IronFormElementBehavior]
});
</script>
</dom-module>
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
_onResponse: function(e) {
this._response = JSON.stringify(e.detail.response, null, 2);
},
_submit: function() {
this._response = null;
this.$.form.submit();
}
});
Polymer({
is: 'multi-listbox',
behaviors: [
Polymer.IronFormElementBehavior
],
properties: {
value: {
type: Array,
value: () => [],
notify: true
},
invalid: {
type: Boolean,
reflectToAttribute: true
}
},
validate: function() {
const isValid = !this.required || !!(this.value && this.value.length > 0);
this.invalid = !isValid;
console.log('invalid', this.invalid);
return isValid;
},
_clearError: function() {
this.invalid = false;
}
});
});
<head>
<base href="https://polygit.org/polymer+1.7.1/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="iron-form/iron-form.html">
<link rel="import" href="paper-button/paper-button.html">
<link rel="import" href="paper-checkbox/paper-checkbox.html">
<link rel="import" href="paper-listbox/paper-listbox.html">
<link rel="import" href="paper-item/paper-item.html">
<link rel="import" href="iron-form-element-behavior/iron-form-element-behavior.html">
<link rel="import" href="iron-validatable-behavior/iron-validatable-behavior.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<style>
multi-listbox,
paper-checkbox,
paper-button {
margin: 0.5em;
}
</style>
<paper-checkbox active="{{_required}}">Required</paper-checkbox>
<form is="iron-form"
id="form"
action="//httpbin.org/get"
on-iron-form-response="_onResponse">
<multi-listbox name="listbox-values" required="[[_required]]">
<paper-item>Item 1</paper-item>
<paper-item>Item 2</paper-item>
<paper-item>Item 3</paper-item>
<paper-item>Item 4</paper-item>
</multi-listbox>
<paper-button raised
on-tap="_submit">Submit</paper-button>
</form>
<pre>[[_response]]</pre>
</template>
</dom-module>
<dom-module id="multi-listbox">
<template>
<style>
:host {
display: block;
}
paper-listbox {
border: solid 2px lightgray;
}
:host([invalid]) paper-listbox {
border: solid 2px var(--error-color, red);
}
</style>
<paper-listbox multi
selected-values="{{value}}"
on-iron-activate="_clearError">
<content></content>
</paper-listbox>
</template>
</dom-module>
</body>
codepen
trying to style the paper-button inside the template, I've tried different sectors and only one is worked so how can i do the styling correctly.
so in the index.html i call iron-ajax element and one the last-response i call a dom-repeat template
<iron-ajax id="aj" auto
url="url"
handle-as="json"
last-response="{{ajaxResponse}}"
contentType="text/HTML"
debounce-duration="300"></iron-ajax>
<div class="video">
<template is="dom-repeat" items="[[ajaxResponse]]" >
<paper-card image="[[item.fields.image]]">
<feed-bdy items="[[item]]"></feed-bdy>
and in the feed-bdy.html :
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-styles/typography.html">
<dom-module is="feed-bdy">
<style >
:host{
--paper-button-ink-color: var(--paper-pink-a200);
paper-button.custom:hover{ background-color: var(--paper-indigo-100) !import; }
}
:host paper-button.rea:hover{
--paper-button-ink-color: var(--paper-pink-a200);
color: red
}
--paper-button.custom:hover {
background-color: var(--paper-indigo-100) !import;
color: white !important;
}
paper-button:hover{
background-color:red !important;
}
</style>
<template id="repeater" is="dom-repeat" items="{{items}}">
<div class="card-content">
<div class="ar-header">
<h3> [[items.fields.title]]</h3>
</div>
<div class="content-bdy"></div>
</div>
[[_renderHTML(items)]]
<div class="card-actions">
<paper-button class="custom">إقراء المزيد !</paper-button>
<paper-button>
شارك
<iron-icon icon="reply"></iron-icon>
</paper-button>
</div>
</template>
<script>
Polymer({
is: 'feed-bdy',
properties: {
artId:{
type : String,
observer: '_renderHTML'
}
},
listeners :{
},
_renderHTML: function(items) {
// firstp to get only the first pargarph to put in the home page
var ss= items.fields.body;
//console.log(this.$$(".card-content"));
var firstp = ss.substring(0,ss.search("</p>")+4);
this.$$(".content-bdy").innerHTML += firstp;
},
_toggle : function(e){
var id = Polymer.dom(e).localTarget.title;
//console.log(id);
var moreInfo = document.getElementById(id);
// console.log(moreInfo);
var iconButton = Polymer.dom(e).localTarget;
iconButton.icon = moreInfo.opened ? 'hardware:keyboard-arrow-up'
: 'hardware:keyboard-arrow-down';
moreInfo.toggle();
}
});
</script>
</dom-module>
There are a few issues with your CSS:
import! should be important!
Mixins and custom properties need to be defined within a selector:
INCORRECT
<style>
--paper-button: {
/** Some styles */
}
--paper-button-ink-color: blue;
</style>
CORRECT
<style>
:host {
--paper-button: {
/** Some styles */
}
--paper-button-ink-color: blue;
}
</style>
Mixins and custom properties are not selectors:
INCORRECT
<style>
--paper-button.special-css-class {
/** Some styles */
}
</style>
Instead, you can use the .special-css-class as your selector, and define your mixin/custom property for any element that matches:
CORRECT
<template>
<style>
.special-css-class {
--paper-button: {
/** Some styles */
}
--paper-button-ink-color: blue;
}
</style>
<paper-button class="special-css-class"></paper-button>
<!-- This button won't have your custom styles! -->
<paper-button></paper-button>
</template>
At least for paper-button, you need not use custom properties/mixins if you just want to specify the color and background color:
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link href="paper-button/paper-button.html" rel="import">
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<style>
paper-button {
background-color: purple;
color: red;
}
</style>
<template is="dom-repeat" items="{{items}}">
<paper-button>Click Me</paper-button>
</template>
</template>
<script>
Polymer({
is: 'x-foo',
properties: {
items: {
value: [1, 2, 3, 4]
}
}
});
</script>
</dom-module>
How can I use getElementById in a Polymer custom element?
Here is my element:
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../styles/shared-styles.html">
<dom-module id="bb-calendar">
<template>
<style is="custom-style" include="shared-styles"></style>
<div class="card">
<paper-toolbar>
<div title>Calendar</div>
</paper-toolbar>
<div id="hideme">
<div>this should be hidden</div>
</div>
</div>
</template>
<script>
Polymer({
is: 'bb-calendar',
ready: function() {
document.getElementById("hideme").style.display = 'none';
}
});
</script>
</dom-module>
When I run the code I get this error message: Uncaught TypeError: Cannot read property 'style' of null
Obviously I'm doing something wrong but I don't know what.
I'd use
ready: function() {
this.$.hideme.style.display = 'none';
}
of when the element is inside <template dom-if...> or <template dom-repeat...>
ready: function() {
this.$$('#hideme').style.display = 'none';
}
In the end, I'd use class binding and bind a class to the element and update a property to reflect that change and use CSS to set style.display
<template>
<style>
.hidden { display:none; }
</style>
...
<div class$="{{hiddenClass}}">
<div>this should be hidden</div>
</div>
Polymer({
is: 'bb-calendar',
properties: {
hiddenClass: String,
},
ready: function() {
this.hiddenClass = 'hidden';
}
});
Your problem is actually that your element is not attached to the document DOM when the ready callback is fired. For simply showing/hiding an element you may use the hidden attribute like this: <div hidden$="{{!shouldShow}}">
I have an item bound in my iron-list, when I change a bound property on the object I am expecting to see the change reflected on the screen, but I don't. What am doing wrong?
https://jsfiddle.net/ckqL3a3o/3/
<link rel="import" href="https://cdn.rawgit.com/Download/polymer-cdn/1.2.3.2/lib/polymer/polymer.html">
<link rel="import" href="https://cdn.rawgit.com/Download/polymer-cdn/1.2.3.2/lib/iron-list/iron-list.html">
<script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script>
<script src="https://google.github.io/traceur-compiler/bin/BrowserSystem.js"></script>
<script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script>
<template is="dom-bind" id="app">
<div style="width: 500px; height: 300px; background: #eee; overflow: auto; float:left">
<iron-list items="{{data}}" as="item" style="width: 500px; height: 300px;">
<template>
<p><span>{{item.name}}</span> <span>{{item.value}}</span></p>
</template>
</iron-list>
</div>
</template>
<script type="module">
'use strict';
var app = document.querySelector('#app');
app.data = [{ name: 'item', value: 3 }];
setTimeout(() => app.data[0].value = 4, 2000);
</script>
You need to use Polymers API to modify model data for Polymer to get notified
setTimeout(() => this.set('app.data.0.value', 4), 2000);
See also
- https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#set-path
- https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#array-binding
- https://www.polymer-project.org/1.0/docs/devguide/properties.html#notifysplices