Polymer: Passing properties to child element doesn't work - html

I'm trying to output data from a custom Polymer component <data-component> in an <iron-list> but nothing is shown when I open the page. It works when I pass an array of objects directly to the iron-list like <iron-list items='[{"name": "test1"}, {"name":"test2"}]' >
What am I doing wrong here and is the <template is="dom-bind" id="t"> mandatory?
index.html
<html>
<head>
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../data-component.html">
<link rel="import" href="../../iron-list/iron-list.html">
</head>
<body unresolved>
<template is="dom-bind" id="t">
<data-component>
<!--<iron-list items='[{"name": "test1"}, {"name":"test2"}]' > WORKS -->
<iron-list items="{{data}}" >
<template>
<div>
Name: <span>{{item.name}}</span>
</div>
</template>
</iron-list>
</data-component>
</template>
</body>
</html>
data-component.html
<link rel="import" href="../polymer/polymer.html">
<dom-module id="data-component">
<template>
<content></content>
</template>
</dom-module>
<script>
window.coolData = [
{"name": "Bob"},
{"name": "Tim"},
{"name": "Mike"}
];
Polymer({
is: 'data-component',
properties: {
data: {
value: window.coolData
}
}
});
</script>

I'm going to suggest an alternative answer to what I have already posted. If you want your data-component to always contain the iron-list then you can use this version here. However, if the content of the data-component should be more flexible use my other answer.
If you move the iron-list inside the data-component you can remove the dom-bind in your index.html.
data-component.html
<link rel="import" href="../polymer/polymer.html">
<dom-module id="data-component">
<template>
<iron-list items="{{data}}" >
<template>
<div>
Name: <span>{{item.name}}</span>
</div>
</template>
</iron-list>
</template>
</dom-module>
<script>
window.coolData = [
{"name": "Bob"},
{"name": "Tim"},
{"name": "Mike"}
];
Polymer({
is: 'data-component',
properties: {
data: {
type: Array,
value: window.coolData
}
}
});
</script>
index.html
<body unresolved>
<data-component></data-component>
</body>

You also have to add a data-binding to your data-component. Otherwise, the system does not know that data (in your iron-list) should refer to the data property in your custom element.
<data-component data="{{data}}">
<iron-list items="{{data}}" >
...
</iron-list>
</data-component>
The dom-bind is necessary if you want to have data-binding outside of a Polymer element, which seems to be the case here.
You should also make sure that the data property is configured to notify changes and that its type is set to Array.
Polymer({
is: 'data-component',
properties: {
data: {
type: Array,
value: window.coolData,
notify: true
}
}
});

Related

Polymer 1.x: accessing element within dom-if

Here is my JSBin
Click on the "First Name: James" text.
I have an input element within dom-if. In an event, I am making dom-if to pass and so the element will come into existence but I cannot access the input element immediately after making the dom-if condition pass.
May be I need to know when the dom-if is actually evaluated and why the element does not exist even if the condition has become true.
<!doctype html>
<head>
<meta charset="utf-8">
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import">
<link href="iron-form/iron-form.html" rel="import">
<link href="paper-input/paper-input.html" rel="import">
</head>
<body>
<dom-module id="x-element">
<template>
<style></style>
<template is="dom-if" if="{{!editMode}}">
<span id="name" on-tap="_makeEditable">{{name}}: {{value}}</div>
</template>
<template is="dom-if" if="{{editMode}}">
<paper-input id="input" label="{{name}}" value="{{value}}"></paper-input>
</template>
</template>
<script>
(function(){
Polymer({
is: "x-element",
properties: {
editMode: {
type: Boolean,
value: false
},
name: {
type:String,
value:"First Name"
},
value: {
type:String,
value:"James"
}
},
_makeEditable: function() {
this.editMode = true;
//how to find the input element here
//this.$$('#input').querySelector("input").focus();
//this.$.input.querySelector("input").focus();
}
});
})();
</script>
</dom-module>
<x-element></x-element>
</body>
This is because setting this.editMode to true does not update the DOM instantaneously.
You should be running your selector asynchronously, so that Polymer has some time to update the DOM, such as:
this.async(function() {
this.$$('#input').focus();
})
Fiddle here.

Subset hyphenated JSON element in Polymer data binding

Consider the following JSON:
{"EMD-4091":["EMD-4084","EMD-4090"]}
which is the result of a fictitious iron-ajax call as follows:
<iron-ajax
auto
url="http://me.com/get/EMD-4091"
handle-as="json"
last-response="{{my_data}}">
</iron-ajax>
Suppose I need to refer to the inner array, say, in a dom-repeat: how would I refer to 'EMD-4091' in a data binding? e.g.
<template is="dom-repeat" items="{{my_data????}}> <!-- what should this be?-->
<p>{{item}}</p>
</template>
If the data wasn't hyphenated this is a trivial task. The hyphen is the challenge I'm facing.
P
The data binding can still parse the hyphenated key without a problem, so your binding would be:
items="{{my_data.EMD-4091}}"
HTMLImports.whenReady(() => {
"use strict";
Polymer({
is: 'x-foo',
properties : {
my_data: {
type: Array,
value: () => ({"EMD-4091":["EMD-4084","EMD-4090"]})
}
}
});
});
<head>
<base href="https://polygit.org/polymer+1.7.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<template is="dom-repeat" items="[[my_data.EMD-4091]]">
<div>[[item]]</div>
</template>
</template>
</dom-module>
</body>
codepen

Computed Binding with Polymer

This is an excerpt of my codes:
<template is="dom-bind">
<iron-ajax auto
url="####"
params=""
handle-as="json"
last-response="{{ajaxResponse}}"></iron-ajax>
<template is="dom-repeat" items="[[ajaxResponse.Items]]">
<div>
[[_formatDate(item.ID.N)]]
</div>
</template>
</template>
...
<script>
Polymer({
is: 'home-view',
_formatDate: function(ID) {
console.log("TEST");
return "TEST";
}
});
</script>
I am getting this Console Warning:
[Warning] [dom-bind::_annotatedComputationEffect]: – "compute method `_formatDate` not defined" (data:text/javascript;charset=utf-8,(fu…%0A, line 265, x10)
So it seems that I do not know how to define _formatDate correctly so that it is recognized by Polymer. Can someone please help?
It looks like you're correctly declaring and using _formatDate().
The warning comes from dom-bind, which is intended only for bindings in index.html, not inside dom-module. You should remove the is="dom-bind" from your top template.
<head>
<base href="https://polygit.org/polymer+1.6.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<home-view></home-view>
<dom-module id="home-view">
<template>
<template is="dom-repeat" items="[[items]]">
<div>[[_formatDate(item)]]</div>
</template>
</template>
<script>
// For cross-browser compatibility, HTMLImports.whenReady()
// needed in index.html only
HTMLImports.whenReady(function() {
Polymer({
is: 'home-view',
properties: {
items: {
type: Array,
value: function() { return ['hello', 'world']; }
}
},
_formatDate: function(id) {
console.log('id', id);
return id;
}
});
});
</script>
</dom-module>
</body>

Polymer iron-list dynamically adding items?

I'm trying to migrate some code from Polymer 0.5 to 1.x, this means moving from core-list to iron-list. However, I can not figure out an iron equivalent to how I was adding items to the core-list.
<core-list height="85">
<template>
<div class="{{ {selected: selected} | tokenList }}" style="padding:5px;"><paper-fab mini icon="arrow-forward" title="arrow-forward"></paper-fab> <!--{{index}}-->{{model.name}}</div>
</template>
</core-list>
which is called updated via...
document.querySelector('core-list').data = $.parseJSON('[{"name":"One"},{"name":"Two"}]');
Anyone have any suggestions?
Update : Jul-23-2015 12:20PM PST
#Zikes
Following the suggestion posted, I have the following.
<dom-module id="my-element">
<template>
<iron-list items="[[myItems]]" as="item">
<template>
<div>[[item.name]]</div>
</template>
</iron-list>
</template>
<script>
Polymer({
is:'my-element',
properties: {
myItems: Array
},
addItem: function(item) {
this.push('myItems', {name: item});
}
});
</script>
</dom-module>
If this is setup right, how would I go about calling the addItem method from elsewhere?
Update : Jul-23-2015 1:58PM PST
#Zikes
Following is my current code. While I can manipulate the array, values added to it in the ready or addItem method are not being displayed.
<dom-module id="fnord-element">
<template>
<iron-list items="[[myItems]]" as="item">
<template>
<div class="item">[[item.name]]</div>
</template>
</iron-list>
</template>
<script>
Polymer({
is:'fnord-element',
properties: {
myItems: {
type: Array,
notify: true
}
},
addItem: function(item) {
//this.push("myItems", {"name":item});
this.myItems=[{name:item}];
alert(this.myItems[0].name);
//alert(item);
},
ready: function() {
//alert('fnord');
this.myItems=[{name:"One"},{name:"Two"}];
}
});
</script>
</dom-module>
<fnord-element id="fnord"></fnord-element>
<paper-button raised onclick="document.querySelector('#fnord').addItem('John Doe');">Test</paper-button>
iron-list uses the items property to generate its items, similar to dom-repeat. What you can do is simply bind it to an Array in your component, like so:
<dom-module id="my-element>
<template>
<iron-list items="[[myItems]]">
<template>
<div>[[item]]</div>
</template>
</iron-list>
</template>
<script>
Polymer({
is:'my-element',
properties: {
myItems: Array
}
});
</script>
</dom-module>
Then, just follow the rules for modifying an Array property and you're all set!

app-router not working imperatively way

I have this Polymer custom element:
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/core-animated-pages/core-animated-pages.html">
<link rel="import" href="../../../bower_components/app-router/app-router.html">
<polymer-element name="custom-pages" attributes="selected">
<template>
<link rel="stylesheet" href="custom-pages.css">
<app-router id="router" bindRouter core-animated-pages transitions="cross-fade-all" trailingSlash="ignore">
<template repeat="{{page in pages}}">
<app-router path="{{page.path}}" import="{{page.url}}"></app-router>
</template>
</app-router>
</template>
<script>
(function() {
Polymer({
selected: 0,
pages: [{
path: "/home",
url: '../custom-home/custom-home.html'
}, {
path: "/about",
url: '../custom-about/custom-about.html'
}],
selectedChanged: function(oldValue, newValue) {
router = this.$.router;
router.go(this.pages[newValue].path);
}
});
})();
</script>
</polymer-element>
Elements custom-home and custom-about should be lazy loaded when "selected" change, but not is happening (no page is displayed).
You have a syntax error in your template definition, nested tags are to be app-route rather than app-routeR:
<app-router id="router" ...>
<template repeat="{{page in pages}}">
<!-- ⇓ superfluous r, nested are app-route -->
<app-router path="{{page.path}}" import="{{page.url}}"></app-router>
<!-- SHOULD BE: -->
<app-route path="{{page.path}}" import="{{page.url}}"></app-route>
</template>
</app-router>
Currently you have created a bundle of empty routers.
Plus, the documentation says:
If you use go(path, options) you should also set the mode to hash or pushstate on the router.
I am not sure if this affects your case, since you do not seem to pass options.
Hope it helps.