how to pass data from host element to child element - polymer

Having trouble getting my data to work across elements. Say I have an object "records" in my host element. It is usable in that element no problem. But when I try to spin off the view into a separate element, it no longer works.
Here's an example snippet of code. The .template part works fine but I'm not able to replicate the functionality in the child element .my-list. When I try, nothing happens.
<dom-module id="host-element">
...
<template is="dom-repeat" items="{{records}}">
<p>{{item.userName}} - {{item.number}}</p>
</template>
<my-list></my-list>
<script>
Polymer({
is: 'host-element',
ready: function() {
this.records = [
{userName: 'Bob'},
{userName: 'Sally'}
];
}
});
</script>
</dom-module>
If I try simply taking the current .template code and placing it into .my-list, it doesn't work.
I assume I need someway to bind the data into the child element, but I'm not able to figure this out. Adding a: record="{{records}}" to the tag, and then using that in the child element didn't work.
Imagine this is pretty simple, just can't find the answer in the documentation.

It's important that each element's top-level template is a plain template (not is="dom-repeat" or other specialization), otherwise, it should be straightforward:
<link rel="import" href="//polygit.org/components/polymer/polymer.html">
<i>(Requires Chrome)</i>
<host-element></host-element>
<dom-module id="my-list">
<template>
<template is="dom-repeat" items="{{records}}">
<p>{{item.userName}} - {{item.number}}</p>
</template>
</template>
<script>
Polymer({
is: 'my-list'
});
</script>
</dom-module>
<dom-module id="host-element">
<template>
<my-list records="{{records}}"></my-list>
</template>
<script>
Polymer({
is: 'host-element',
ready: function() {
this.records = [{userName: 'Bob'}, {userName: 'Sally'}];
}
});
</script>
</dom-module>

Related

Multiple elements which can be called via one element

I have a set of Polymer 1.x components which act as fillable forms. Each form can be called via <form-one></form-one>, <form-two></form-two> etc...
<dom-module id="form-one">
<template>
form content
</template>
</dom-module>
<script>
Polymer({
is: "form-one"
});
</script>
I'm looking for a solution to combine them and to have only one element and call the forms like:
<form-handler form="form-one"></form-handler>
Where to start? And is it also possible to keep the dom modules in separated files?
Thanks in advance.
You can have your element like this:
<dom-module id="form-handler">
<template>
<div id="formContainer">
</template>
</dom-module>
<script>
Polymer({
is: "form-handler",
properties:{
form: {type:String, observer:'_formChanged'}
},
_formChanged: function(){
var formElement = document.createElement(this.form);
this.$.formContainer.empty();
this.$.formContainer.append(formElement);
}
});
</script>

On attached, `this.$` an empty object

I'm trying to observe added and removed dom nodes to my custom Polymer element without success. I've noticed that the this.$ is an empty object.
Polymer({
is: 'dramatic-view',
attached: function () {
this._observer = Polymer.dom(this.$.contentNode).observeNodes(function (info) {
console.log('kromid info', info);
});
}
});
The callback is being called only once (even tho I change content afterwards) with the following strange parameters:
I was following the docs here.
this.$ is a hash of elements in your template that have an id attribute (see Automatic node finding).
So, for this.$.contentNode to exist, you need an element with id="contentNode" in your <dom-module>'s <template>, and it must not be inside a dom-if or dom-repeat template:
<dom-module id="x-foo">
<template>
<content id="contentNode"></content>
</template>
</dom-module>
Nodes created dynamically (i.e., those inside dom-if or dom-repeat) must be queried with this.$$() (e.g., this.$$('#contentNode')). If you're trying to set them up in the attached callback, you'll need to wait until after the nodes are stamped, which could be observed with Polymer.RenderStatus.afterNextRender().
<dom-module id="x-foo">
<template>
<template is="dom-if" if="[[useDynamicContent]]">
<content id="contentNode"></content> <!-- unavailable to this.$ -->
</template>
</template>
<script>
Polymer({
is: 'x-foo',
attached: function() {
Polymer.RenderStatus.afterNextRender(this, function() {
var contentNode = this.$$('#contentNode');
if (contentNode) {
contentNode.observeNodes(...);
}
});
}
});
</script>
</dom-module>
To trigger the node observer, use Polymer's DOM API like this:
Polymer.dom(this).appendChild(node);
Polymer.dom(this).removeChild(node);
codepen
UPDATE It seems you're integrating Polymer with Elm, and expecting to see the observer callback for node-changes made my Elm. You'll need to hook Elm's calls to appendChild/removeChild somehow so that it uses Polymer's DOM API.

Polymer - Select DOM Element from if template

I'm learning Polymer. I have a view that is setup like this:
my-view.html
<dom-module id="my-view">
<template>
<template is="dom-if" if="[[ areAvailable ]]">
<my-component id="myComponent"></my-component>
<button type="button" on-click="onButtonClick">Test</button>
</template>
<template is="dom-if" if="[[ !areAvailable ]]">
<div>Move along</div>
<template>
</template>
<script>
Polymer({
is:'my-view',
properties: {
areAvailable: Boolean
},
onButtonClick: function() {
this.$.myComponent.test();
}
});
</script>
</dom-module>
This view shows my-component based on the areAvailable flag. If a user clicks the "Test" button, I need to execute a function in my-component. my-component is setup like this:
my-component.html
<dom-module id="my-component">
<template>
<h1>hello there!</h1>
</template>
<script>
Polymer({
is:'my-component',
test: function() {
alert('voila!');
}
});
</script>
</dom-module>
My challenge is, my approach works IF my-component is not inside of an "if" template. When my-component is inside of an "if" template, I get an error that says:
TypeError: Cannot read property 'test' of undefined
What am I doing wrong?
Note: Nodes created dynamically using data binding (including those in dom-repeat and dom-if templates) are not added to the this.$ hash. The hash includes only statically created local DOM nodes (that is, the nodes defined in the element’s outermost template).
Source: https://www.polymer-project.org/1.0/docs/devguide/local-dom.html#node-finding
Since you have already added a listener to the click event on your button, you can redefine that listener like this:
Polymer({
...
onButtonClick: function() {
// The this.root here refers to the local dom
// It is highly advised that you use Polymer.dom(<node>) when doing dom manipulations
Polymer.dom(this.root).querySelector('#myComponent').test();
}
});
Polymer have this simple function...
this.$$('#myComponent')
https://www.polymer-project.org/1.0/docs/devguide/local-dom#node-finding

Polymer element is unregistered

I've created an element to display the results of an API call, but it not rendering. I've used the 'unregistered element' bookmarklet from the Polymer team which is showing this as unregistered. I'm using this within the Polymer starter kit.
I'm sure its a simple oversight on my behalf that I'm just not seeing.
The element is is listed in the elements.html file and is used in the main index.html file like so.
<section data-route="driver-standings">
<driver-standing></driver-standing>
</section>
The element
<dom-module id="driver-standing">
<template>
<style>
:host {
display: block;
}
</style>
<iron-ajax
auto
url="http://ergast.com/api/f1/current/driverStandings.json"
handle-as="json"
last-response="{{data}}"></iron-ajax>
<template is="dom-repeat" items="{{driverList}}">
<span>[[item.Driver.givenName]]</span> <span>[[item.Driver.familyName]]</span>
<template>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'driver-standing',
properties: {
data: {
},
driverList: {
computed: 'processDrivers(data)'
}
},
processDrivers: function (data){
console.log("processDrivers")
return data.MRData.StandingsTable.StandingsLists[0].DriverStandings;
}
});
})();
</script>
</dom-module>
Any help much appreeciated
I missed the closing / on the template tag.
<template is="dom-repeat" items="{{driverList}}">
<span>[[item.Driver.givenName]]</span> <span>[[item.Driver.familyName]]</span>
<template>
became...
<template is="dom-repeat" items="{{driverList}}">
<span>[[item.Driver.givenName]]</span> <span>[[item.Driver.familyName]]</span>
</template>
Easily missed :)
Your dom-repeat - template should look some kind of this:
You should have your items you want to display in the item tag and as Polymer goes throw your Array it safes each Object under the name defined under the as - tag, so you can access the Object inside of your template binding with the name in curly brackets, like {{driver}}
<template is="dom-repeat"
items="{{driverList}}"
as="driver">
<p>{{driver}}</p>
</template>

Polymer 1.0: How to style distributed nodes with #apply?

We have a custom element that is making an AJAX call to fetch some html generated on the server side and then injected into its light dom via Polymer.dom(this).innerHTML. The response coming from the server has another custom element in it that exposes a CSS property for theming purposes. On the main page, we're setting the value for the property, but it doesn't appear to be working. How do we get Polymer to style dynamically added light DOM elements that are distributed by another element.
index.html
<style is="custom-style">
x-bar {
--mixin-property: {
background: red;
};
}
</style>
...
<body>
<x-baz>
</x-baz>
</body>
x-baz.html
<dom-module id="x-baz">
<template>
<x-foo></x-foo>
</template>
</dom-module>
<script>
Polymer({
is: "x-baz"
});
</script>
x-foo.html
<dom-module id="x-foo">
<template>
<iron-ajax auto url="..." last-response="{{response}}"></iron-ajax>
<content></content>
</template>
</dom-module>
<script>
Polymer({
is: "x-foo",
properties: {
response: {
type: String,
obeserver: 'responseChanged'
}
},
responseChanged: function(newVal)
Polymer.dom(this).innerHTML = newVal;
}
});
</script>
x-bar.html
<dom-module id="x-bar">
<style>
.elementToStyle {
#apply(--mixin-property);
}
</style>
<template>
<div class="elementToStyle">
...
</div>
</template>
</dom-module>
</script>
Polymer({
is: "x-bar"
});
</script>
The iron-ajax call returns <x-bar> ... </x-bar>.
I would expect the div inside the x-bar that comes back from the AJAX response to have a red background, but it doesn't seem to be working. What do we need to adjust to make this work correctly?
Thanks in advance!