Polymer access elements within vaadin-grid - polymer

Working jsbin illustrating the problem: http://jsbin.com/nomewa/3/edit?html,console,output
I am trying to set the innerHTML of notworking span inside of a template that makes up the vaadin-grid. It does not currently seems to be possible to bind to on-change of vaadin-checkbox when said vaadin-checkbox lies within vaadin-grid since I cannot even access the element within the grid.

It does not currently seems to be possible to bind to on-change of vaadin-checkbox when said vaadin-checkbox lies within vaadin-grid since I cannot even access the element within the grid.
You can use declarative event bindings inside the column tempates, so you don’t have to have a reference to the actual stamped element.
Something like this:
<vaadin-grid-column>
<template>
<vaadin-checkbox on-checked-changed="_myListener">Checkbox</vaadin-checkbo>
</template>
</vaadin-grid-colum>

This is a great way to try some codes (jsbin :) Here this code works but I do not know is it going to fit your need. (I cut and copied only changed parts :
At the property declaration, you may set a pre-value to notWorking property. Then you may change it with dynamically in a function.
<iron-ajax url="https://randomuser.me/api?results=10" last-response="{{response}}" auto></iron-ajax>
<span id="working">Working</span>
<vaadin-grid id="grid" items="{{response.results}}" style="height: auto;">
<vaadin-grid-column>
<template class="header">Name</template>
<template>[[item.name.first]] [[item.name.last]] <span>{{notWorking}}</span></template>
</vaadin-grid-column>
</vaadin-grid>
</template>
<script>
class MyTest extends Polymer.Element {
static get is() { return 'test-component'; }
ready() {
super.ready();
this.set('notWorking',"test")
debugger;
}
}
Here the working link

Related

How can I allow a polymer component to contain dynamic elements?

In polymer, let's say I have a container element <x-container>, and two child elements <a-child>, <b-child>. In an element, I want to be able to specify that it contains either <a-child> or <b-child> (it will never have both).
For example, it could look like:
1. <x-container><a-child></a-child></x-container>
or,
2. <x-container><b-child></b-child></x-container>.
Since <x-container> has a lot of code, I don't want to duplicate it, but want to be able to use an <x-container> like this:
<x-container type = 'a-child'></x-container> which would then have the same behavior as the first item mentioned. How could I achieve this functionality?
Just instanciate it when you have the information which one its going to be!
//in your x-container component
observers: ['_typeChanged(type)'],
_typeChanged: function(type) {
var child = this.create(type);
Polymer.dom(this.root).appendChild(child);
}
Or you use a slot then you could do smth like this
parent component
<x-container>
<template is="dom-if" if="[[_isA()]]"><a-child></a-child></template>
<template is="dom-if" if="[[_isB()]]"><b-child></b-child></template>
</x-container>
and in your x-container´s template just simply put a slot the child will be rendered within the slot
<slot></slot>

How to access Polymer functions from JS

Sorry if this comes out a bit garbled, I'm not sure how to ask this question.
What I am trying to do is keep the DOM synced with a localStorage value, and am updating the localStorage value with an interact.js mouse event.
Currently, I am able to properly set the localStorage value, but am having problems updating the DOM.
My current build is within the Polymer framework, so I am having trouble selecting shadow DOM content.
The DOM tree looks like
PARENT-ELEMENT
# SHADOW ROOT
EL
EL
DIV
CUSTOM ELEMENT
EL
EL
Here are some ways I have failed to solve the problem. The Custom Element is in pure JS, since I am not sure how to properly wrap interact.js function in Polymer:
I tried directly accessing the PARENT-ELEMENT's shadow DOM from the Custom Element in pure JS.
var shadowDOMNode = document.querySelector('PARENT-ELEMENT');
var dom_object_1 = shadowDOMNode.querySelector('#dom_object_1');
dom_object_1.innerHTML = localStorage.dom_object_1;
I tried selecting a helper updateDOM() function from the PARENT Polymer element and running it from the Custom Element's setter directly.
if (event.dy > 0) {
this.$$('PARENT-ELEMENT').updateDOM();
}
Maybe I am taking the wrong approach entirely, but I haven't been able to find analogues for interact.js in using native Polymer functions.
I hope this question was clear enough...
If we ignore the interact.js part of the problem and focus on Polymer, you could probably solve this without coupling the two.
To bind to a localStorage value with Polymer, use the <iron-localstorage> element. In the following example, the localStorage value named flavor_1_amount is loaded and stored into a property named _flavor1Amount. If the value doesn't exist in localStorage or is empty, the <iron-localstorage> element fires an event (iron-localstorage-load-empty), which allows you to bind to a callback (e.g., to initialize it).
<iron-localstorage name="flavor_1_amount"
value="{{_flavor1Amount}}"
use-raw
on-iron-localstorage-load-empty="_initFlavor1Amount">
</iron-localstorage>
In the same element, you could provide an input for the user to update the localStorage value.
<paper-input label="Flavor Amount (mL)" value="{{_flavor1Amount}}"></paper-input>
And you can use <iron-localstorage>.reload() to keep your data binding in sync, assuming it could be changed externally.
See this codepen for a full demo. Check your localStorage from Chrome DevTools:
Generally speaking you should use this.set() or any of the array mutation methods if it's an array in order for the ShadowDOM to be notified properly.
Since you want to perform this update from outside the element itself, imperatively, I'd suggest this:
Expose a couple of methods from your element that you can use to add/remove/change property values from outside your element.
These methods would internally use the proper channels to make the changes.
An example (you can call addItem() to add items from outside your element):
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<dom-module id="x-example">
<template>
<template is="dom-repeat" items="[[data]]">
<div>{{item.name}}</div>
</template>
</template>
<script>
HTMLImports.whenReady(function() {
"use strict";
Polymer({
is: "x-example",
properties: {
data: {
type: Array,
value: [
{name: "One"},
{name: "Two"},
{name: "Three"}
]
}
},
// Exposed publicly, grab the element and use this method
// to add your item
addItem: function(item) {
this.push("data", item);
}
});
});
</script>
</dom-module>
<x-example id="x-example-elem"></x-example>
<script>
setTimeout(function() {
// simply 'grab' the element and use the
// `addItem()` method you exposed publicly
// to add items to it.
document.querySelector("#x-example-elem").addItem({name: "Four"});
}, 2500);
</script>
Important: That being said, this is not the "Polymeric" way of doing stuff as this programming-style is imperative, in constrast with Polymer's style which is more declarative. The most Polymeric solution is to wrap your interact.js functionality in an element itself and use data-binding between your 2 elements to perform the changes.

Call Method of Child Web Component

I'm really having difficulty trying to figure out how to call a function of a nested Polymer web component.
Here's the markup:
<rise-playlist>
<rise-playlist-item duration="5">
<rise-distribution distribution='[{"id":"VGZUDDWYAZHY"}]'></rise-distribution>
</rise-playlist-item>
</rise-playlist>
The rise-distribution component has a canPlay function that I would like to call from inside of rise-playlist.
The dom-module definition of rise-playlist looks like this:
<dom-module id="rise-playlist">
<template>
<content id="items" select="rise-playlist-item"></content>
</template>
</dom-module>
I can successfully access the rise-distribution element like this:
var distribution = Polymer.dom(this.$.items[0]).querySelector("rise-distribution");
However, when I try to call distribution.canPlay(), it says that distribution.canPlay is not a function.
I've defined the dom-module of rise-playlist-item like this:
<dom-module id="rise-playlist-item">
<content id="dist" select="rise-distribution"></content>
</dom-module>
Not sure if I need that <content> tag, although neither works.
Any ideas?
Thx.
I know that there have been a while but I am sure this problems still occurs as it is being viewed number of times.
Probably there is a problem with your component definition. Let me explain.
This is the way you put your child component inside DOM:
<your-child-component></your-child-component>
And and this should be the definition of your component:
Polymer({
is: 'your-child-component',
apiMethod: function() {
//some stuff
}
});
If you by mistake or due copy-paste error mistype the is: 'your-child-component' part, so it will not reflect the <your-child-component> you will get confused becouse your:
this.$$('your-child-component').apiMethod();
will tell you that there is no method you are willing to call.
Polymer correctly identified and selected from DOM <your-child-component> but if you have different is property (like for example is: your_child_component>) it will not attach its API to dom element you selected.
I hope that it will help if anyone ever will encounter this problem.

Is it possible to inject HTML into a polymer component via an attribute?

I'm using one of the core polymer components that basically has:
<polymer-element attributes="label">
<div>{{label}}</div>
as part of the source. I'd like to inject some HTML into this so that it ultimately renders as:
<div>Item <small>Description</small></div>
Is there any way to do this without copying the entire component (which is basically impossible considering the dependency chain)?
Polymer doesn't allow setting HTML inside {{}} expressions because it's a known XSS outlet. However, there are ways around it (1, 2).
I'm not sure there's a great way around this issue but I found something that works. You want to extend the element but also need to modify its shadow dom because of the .innerHTML limitation. Taking paper-button as an example, it has an internal {{label}}. You could extend the element, drill into its shadow dom, and set .innerHTML of the container where {{label}} is set. React to label changing (labelChanged) and call this.super():
<polymer-element name="x-el" extends="paper-button">
<template>
<shadow></shadow>
</template>
<script>
Polymer('x-el', {
labelChanged: function() {
// When label changes, find where it's set in paper-button
// and set the container's .innerHTML.
this.$.content.querySelector('span').innerHTML = this.label;
// call paper-button's labelChanged().
this.super();
}
});
</script>
</polymer-element>
Demo: http://jsbin.com/ripufoqu/1/edit
Problem is that it's brittle and requires you to know the internals of the element you're extending.

Polymer document.querySelector not working as expected

Either I am doing something horribly wrong or Polymer just doesn't like me. See following:
<polymer-element name="menu-paper-ui" noscript>
<template>
<paper-dialog heading="Dialog" transition="paper-dialog-transition-bottom">
[ .. ]
</paper-dialog>
<paper-button label="Dialog Bottom" on-tap="{{toggleDialog}}"></paper-button>
</template>
<script>
Polymer('menu-paper-ui', {
toggleDialog : function() {
var dialog = document.querySelector('paper-dialog');
console.log(dialog); //returns null
dialog.toggle();
}
})
</script>
</polymer-element>
Now, I have my reasons to use querySelector. So, if someone can tell me whats going wrong that will be great!
This question is nearly identical to Using querySelector to find nested elements inside a Polymer template returns null.
The short answer is that elements in a polymer-element's template are put into the ShadowDOM of that element, are not not visible to the anything outside of that element. This is so that you can control styling more easily, and element IDs are scoped.
You can either give the dialog an id and use Polymer's automatic node finding, or use this.shadowRoot.querySelector('paper-dialog').
The Problem is that you can not access the shadow DOM inside a custom element with document.querySelector. See my answer to a similar question.