Polymer: How to loop and render HTML to screen - polymer

I am working on a widget that pulls third party information from a database using json. Once the information has been collected, I plan to loop through the information and create the required HTML code and insert this into the template via a {{variable}}
Now I am getting an unexpected result. When I do this, the html is being displayed as text.
Here is some sudo code of the issue:
<polymer-element name="loop-element">
<template>
{{customerList}}
</template>
<script>
Polymer('loop-element', {
ready: function() {
this.loadCustomerList();
}
customerList:"Loading customer list...",
loadCustomerList: function() {
CustomerNameArray[] = //Get the array from jSon file
i = 0;
do {
this.customerList = "<div>" + customerNameArray[i] + "</div>";
} while (customerNameArray[i]);
}
});
</script>
</polymer-element>
Essentially the DIV's are not being rendered, instead they are being printed to the screen as text:
"<div>Name 1</div>" "<div>Name 2</div>" ... n
Instead of:
Name 1
Name 2
Name n...
You can see a JSBin example here: http://jsbin.com/tituzibu/1/edit
Can anyone recommend how to go about outputting a list to the template?

Polymer v.1.0
/* relative path to polymer.html*/
<link rel="import" href="../bower_components/polymer/polymer.html">
<dom-module id="employee-list">
<style>
/* CSS rules for your element */
</style>
<template>
<div> Employee list: </div>
<template is="dom-repeat" items="{{employees}}">
<div>First name: <span>{{item.first}}</span></div>
<div>Last name: <span>{{item.last}}</span></div>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'employee-list',
ready: function() {
this.employees = [
{first: 'Bob', last: 'Smith'},
{first: 'Sally', last: 'Johnson'}
];
}
});
</script>
doc

You should use Polymer's DOM-based data-binding features rather than creating the markup yourself.
<template repeat="{{customer, i in customers}}">
<div>{{i}}, {{customer.name}}</div>
</template>
http://www.polymer-project.org/docs/polymer/databinding.html#an-example

Maybe a little late...
If you want to stick to your approach you could use this.injectBoundHTML:
<polymer-element name="loop-element">
<template>
<div id='customerList'> </div>
</template>
<script>
Polymer('loop-element', {
ready: function() {
this.loadCustomerList();
}
customerList:"Loading customer list...",
loadCustomerList: function() {
CustomerNameArray[] = //Get the array from jSon file
i = 0;
do {
this.customerList = "<div>" + customerNameArray[i] + "</div>";
} while (customerNameArray[i]);
this.injectBoundHTML( this.customerList,
this.$.customerList);
}
});
</script>
</polymer-element>
However the first approach is better..

In Polymer 3.0 you can do the following:
<dom-repeat items="{{customers}}">
<template>
{{item.name}}
</template>
</dom-repeat>
Any list is binded to the items property of dom-repeat, and item within the template is used to represent the object from the list. You can read more about the dom-repeat on the Polymer 3.0 API reference page here.

Related

how to pass data from host element to child element

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>

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>

How to get the width of a polymer element inside the JS of the polymer element

I have a polymer element and inside its Javascript I am trying to find its width and height as it is inside the DOM. I tried many ways but I always get 0 back.
...and here's the one which works for me:
Add the Polymer.IronResizableBehavior behaviour to your element (see https://elements.polymer-project.org/elements/iron-resizable-behavior). Then your element will be sent a iron-resize event when it gets sized. In the handler, check to see whether it's not 0; if not, you're golden.
Untested code follows:
<dom-module id="hard-chicken">
<template>
Hello <span>{{name}}</span>
</template>
</dom-module>
<script>
Polymer({
is: 'hard-chicken',
behaviors: [ Polymer.IronResizableBehavior ],
listeners: { "iron-resize": "onWidthChange" },
onWidthChange: function() {
var w = this.offsetWidth;
if (w > 0)
console.log("width is now ", w);
}
});
</script>
This took way, way too long to figure out...
polymer 1.0
<link rel="import" href="../polymer/polymer.html">
<!--
Here's where you'll define your element. You can define multiple elements
if you want, but the package name will be taken from the first custom
element you define in the file. You can also document your element! For
more info, see [the docs](https://ele.io/docs).
#element hard-chicken
-->
<dom-module id="hard-chicken" attributes="name">
<template>
<style>
:host {
font-family: sans-serif;
}
</style>
Hello {{name}}
</template>
<script>
Polymer({is:'hard-chicken',
/**
* The name of the person you want to say hello to.
* #attribute name
* #type string
* #default "Polymer Dev"
*/
name: 'Polymer Dev',
ready: function() {
console.log(this.offsetWidth);
});
</script>
</dom-module>
You probably want to calculate the width in the attached handler of the element, as that comes last when the unit is actually attached to the DOM.
See https://www.polymer-project.org/1.0/docs/devguide/registering-elements.html#initialization-order
attached: function() {
console.log(this.offsetWidth);
}
This should do it:
attached: function() {
this.async(function() {
console.log(this.offsetWidth);
});
}
Read the documentation at:
https://www.polymer-project.org/1.0/docs/devguide/registering-elements#initialization-order
<dom-module id="hard-chicken">
<style>
:host {
font-family: sans-serif;
}
</style>
<template>
Hello <span>{{name}}</span>
</template>
</dom-module>
<script>
Polymer({
is: 'hard-chicken',
/**
* The name of the person you want to say hello to.
* #attribute name
* #type string
* #default "Polymer Dev"
*/
properties: {
name: {
value : 'Polymer Dev',
type: String
}
},
_getWidth: function () {
console.log(this.offsetWidth);
},
ready: function() {
this.async(this._getWidth, 500);
}
});
</script>
<link rel="import" href="../polymer/polymer.html">
<!-- You can import core and paper elements -->
<link rel="import" href="../core-ajax/core-ajax.html">
<!--
Here's where you'll define your element. You can define multiple elements
if you want, but the package name will be taken from the first custom
element you define in the file. You can also document your element! For
more info, see [the docs](https://ele.io/docs).
#element hard-chicken
-->
<polymer-element name="hard-chicken" attributes="name">
<template>
<style>
:host {
font-family: sans-serif;
}
</style>
Hello {{name}}
</template>
<script>
Polymer('hard-chicken', {
/**
* The name of the person you want to say hello to.
* #attribute name
* #type string
* #default "Polymer Dev"
*/
name: 'Polymer Dev',
ready: function() {
console.log(this.offsetWidth);
}
});
</script>
</polymer-element>

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!

Polymer 1.0 services issue

I'm working on a reddit client using polymer to check out web compoments technologies. I started with the 0.5 version and got back on this project recently. That when I found out that polymer had the 1.0 released so I started over (as it wasn't that advanced anyway).
I have a service that use the iron-ajax to request reddit api and look for the posts. Here is the code :
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/iron-ajax/iron-ajax.html">
<dom-module id="reddit-list-service">
<template>
<iron-ajax
url='https://www.reddit.com/new.json'
handle-as='json'
debounce-duration="300"
on-response='handleResponse'
debounce-duration="300"
auto>
</iron-ajax>
</template>
</dom-module>
<script>
(function () {
Polymer({
is: 'reddit-list-service',
properties: {
modhash: {
type: String,
value: function() {
return '';
}
},
posts: {
type: Array,
value: function () {
return [];
}
},
after: {
type: String,
value: function () {
return '';
}
}
},
// Update object properties from the ajax call response
handleResponse: function (resp) {
this.properties.modash = resp.detail.response.data.modhash;
this.properties.posts = resp.detail.response.data.children;
this.properties.after = resp.detail.response.data.after;
this.post = this.properties.posts; // just to try
console.log(this.properties.posts);
}
});
})();
</script>
My log shows me that I get posts from the API and that's great!
Here's the issue when I want to use this service to make a list out of the posts array I can't figure out how to get them into my list compoment which is below :
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../reddit-list-service/reddit-list-service.html">
<dom-module id="reddit-post-list">
<template>
<reddit-list-service posts="{{posts}}">
</reddit-list-service>
<template is="dom-repeat" id="post-list" posts="{{posts}}">
<p>{{post.author}}</p>
<template>
</template>
</dom-module>
<script>
(function () {
Polymer({
is: 'reddit-post-list',
properties: {
},
});
})();
</script>
I've tried several think I saw in the documentation but I can't figure out what's wrong the author property doesn't show up.
Any clue?
You have a few things that aren't quite right here. In reddit-post-list you are not using the dom-repeat template correctly. See below:
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="reddit-list-service.html">
<dom-module id="reddit-post-list">
<template>
<reddit-list-service posts="{{posts}}"></reddit-list-service>
<template is="dom-repeat" items="[[posts]]">
<p>{{item.data.author}}</p>
</template>
</template>
</dom-module>
<script>
Polymer({
is: "reddit-post-list"
});
</script>
You need an attribute called items which is the array the dom-repeat will iterate over. Inside the iteration you need to refer to item as this is the array item for the current iteration. Here are the docs.
For you reddit-list-service, you need to set the the reflectToAttribute and notify attributes to true on your posts property. This means that any changes to this property are reflected back on the posts attribute on the reddit-list-service element. See here for more information.
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="bower_components/iron-ajax/iron-ajax.html">
<dom-module id="reddit-list-service">
<template>
<iron-ajax auto url="https://www.reddit.com/new.json" handle-as="json" on-response="handleResponse"></iron-ajax>
</template>
</dom-module>
<script>
Polymer({
is: "reddit-list-service",
properties: {
modhash: {
type: String,
value: ""
},
posts: {
type: Array,
value: function () {
return [];
},
reflectToAttribute: true, // note these two new attributes
notify: true
},
after: {
type: String,
value: ""
}
},
// Update object properties from the ajax call response
handleResponse: function (resp) {
this.modash = resp.detail.response.data.modhash;
this.posts = resp.detail.response.data.children;
this.after = resp.detail.response.data.after;
}
});
</script>
I have also tidied up the following things:
Removed the immediately called function wrapper from the <script> tags as these are not needed.
When referring to properties in your element you only need to use this.PROPERTYNAME rather than this.properties.PROPERTYNAME.
Having looked at the JSON returned, it appears that the author property is on the another property called data.
When you declare a value for a property in your element, you only need to have a function that returns a value if the property type is an Object or Array.