Polymer paper-input does not update nested property - polymer

Does paper-input support nested properties? For example,
<paper-input label="FIRST NAME" value="{{client.name}}"></paper-input> //client object is updated
<paper-input label="LAST NAME" value="{{client.address.street}}"></paper-input> //client object is not updated
client.name is updated when user enters text into paper-input but client.address.street is not updated when user enters text into paper-input. i.e. client object only contains {name: 'xxx} and not {name: 'xxx', address: {street: 'abc'}}
Is there any documentation out there that mentions the above limitations or did I do something wrong? Thanks!

Polymer doesn't provide a way to bind directly to an array item. You have to use data binding helper elements from polymer (like template repeaters) for nested scopes.
Use one of the following ways to interact with arrays in a data binding:
The dom-repeat helper element lets you create a instance of a template for each item in an array. Inside a dom-repeat instance, you can bind to the properties of the array item.
<dom-repeat items="{{client}}" as="client">
<template>
<paper-input label="FIRST NAME" value="{{client.name}}"></paper-input>
<paper-input label="LAST NAME" value="{{client.address.street}}"></paper-input>
</template>
</dom-repeat>
The iron-list displays a virtual, 'infinite' list. The template inside the iron-list element represents the DOM to create for each list item.
<iron-list items="{{client}}" as="client">
<template>
<paper-input label="FIRST NAME" value="{{client.name}}"></paper-input>
<paper-input label="LAST NAME" value="{{client.address.street}}"></paper-input>
</template>
</iron-list>
If you initialize a property i.e. an object or array value using a function, it will ensure that each element gets its own copy of the value, rather than having an object or array shared across all instances of the element. You don't have to user helper element as above:
client: {
type: Object,
value: function() {
return {
"name": "",
"address": {
"street": ""
}
};
}
}
Demo

Related

Complete example of Polymer Two Way Binding

The polymer documentation has the following two way binding example:
<script>
Polymer({
is: 'custom-element',
properties: {
someProp: {
type: String,
notify: true
}
}
});
</script>
...
<!-- changes to "value" propagate downward to "someProp" on child -->
<!-- changes to "someProp" propagate upward to "value" on host -->
<custom-element some-prop="{{value}}"></custom-element>
I'm looking for a complete example that includes the design of the child, programmatic and interactive events the can cause upward and downward propagation of the `{{value}} property, and a demo of of the complete setup / example.
Here are some examples on js fiddle that demonstrate different ways of binding:
Two-way binding:
https://jsfiddle.net/tej70osf/
One-way binding: notify is not set on value property of the child element:
https://jsfiddle.net/tej70osf/1/
One-way binding: notify is set to true true on value property of the child element however the value property is bound using square brackets [[value]] instead of {{value}}:
https://jsfiddle.net/tej70osf/2/
Hope that helps
<dom-module id="user-demo">
<template>
<paper-input label="FIRST NAME" value="{{firstName}}"></paper-input>
</template>
</dom-module>
<user-demo></user-demo>
In your javascript code:
Polymer({
is: 'user-demo',
properties: {
firstName: {
type: String,
value: 'John',
notify: true
}
}
});
Check out the following fiddle for the full example:
https://jsfiddle.net/meenakshi_dhanani/6ffwh0qv/
I tried to use more polymer elements and two way binding. Hope it helps

How to reload / refresh an iron-list in Polymer 1.0?

I have added an item to my data property bound to an iron-list.
this.data.push(item); // add new item to array
Now the data item has been added but the list will not refresh / reload to show new item added to data array. How do you reload the iron-list? Also couldn't seem to find a method on the iron-list API page. I've tried the following but with no joy...
var list = this.querySelector("iron-list");
list.fire('refresh');
list._refresh();
My data property is defined as follows:
Polymer({
is: "page-list",
properties: {
data: {
type: Array,
notify: true
}
The template structure is:
<iron-ajax url="./data.json" last-response="{{data}}" auto></iron-ajax>
<iron-list items="[[data]]" as="item" class="fit">
<template>
<div class="row">
<p>[[item.name]]</p>
</div>
</template>
</iron-list>
You will need to use a Polymer function to add a new item, like this -
this.push('data', item);
Mutations to the items array itself (push, pop, splice, shift,
unshift) must be performed using methods provided on Polymer elements,
such that the changes are observable to any elements bound to the same
array in the tree.
You can read more from here.

Get multiple values of selected paper-radio-button

I have a dom-repeat element that creates a paper-radio-group with a couple of paper-radio-buttons. These radio-buttons each contains two pieces of unique information loaded from an array. Model name and price. I need to be able to load the model name and price of the selected radio-button.
I'm able to load the name of the selected model but I can't figure out how to do it with the price at the same time. Here is the code I currently have that displays the name:
<paper-radio-group class="layout vertical" id="modelgrp" selected="{{selected}}" >
<template is="dom-repeat" items="{{models}}" >
<paper-radio-button name="{{item.model}}" id="modelsel"><span>{{item.model}}</span> <div class="paper-font-caption"><span>{{item.price}}</span> SEK</div></paper-radio-button>
</template>
</paper-radio-group>
<paper-item><span>{{selected}}</span></paper-item>
I need to be able to call the item.price of the selected item just like I call the item.model by writing {{selected}}.
I was sent this link as it is sort of answering my question but I don't really understand the code and how to apply it to mine.
Use selected-item and add a conditional attribute for each value (model and price) onto the paper-radio-button element:
<paper-radio-group class="layout vertical" selected-item="[[selectedItem]]">
<template is="dom-repeat" items="[[models]]" >
<paper-radio-button name="{{item.model}}" model$="[[item.model]]" price$="[[item.price]]"><span>[[item.model]]</span> <div class="paper-font-caption"><span>[[item.price]]</span> SEK</div></paper-radio-button>
</template>
</paper-radio-group>
<paper-item><span>[[model]]</span></paper-item>
<paper-item><span>[[price]]</span></paper-item>
Then setup an observer to monitor changes to selectedItem and set the two values you want to capture as follows:
...
observers: [ '_selectedItemChanged(selectedItem)' ],
_selectedItemChanged: function(el) {
this.price = el.getAttribute('price');
this.model = el.getAttribute('model');
},
...

Data binding between published properties of two custom elements inside an auto binding template - Polymer 1.0

Problem: I have an auto binding template in my main index.html page. Inside the template I am using two of my custom elements. One element is the producer of some data and the other one is the consumer of that data. These custom elements expose published/declared properties for each other to use and bind to. I was able to do that in Polymer 0.5 fairly easily (an example shown below). How do I do the same in Polymer 1.0?
How I used to do in Polymer 0.5?
In Polymer 0.5 I used to data bind between published properties of two custom elements using curly brace syntax and then inside it used the auto node finding concept to directly bind to other element's published property. An example shown below,
<template is="auto-binding">
<my-navigation selectedLabel="Home" id="my_navigation"></my-navigation>
<my-scaffold toolbartitle="{{ $.my_navigation.selectedLabel }}" id="my_scaffold"></my-scaffold>
</template>
I tried something similar in Polymer 1.0 as shown in the example below
<template is="dom-bind">
<my-navigation selectedLabel="Home" id="my_navigation"></my-navigation>
<my-scaffold toolbartitle="{{ $.my_navigation.selectedLabel }}" id="my_scaffold"></my-scaffold>
</template>
But it throws an error:-
Uncaught TypeError: Cannot read property '$' of undefined
You can't do $.* bindings inside the template in Polymer 1.0. Instead, either refactor or use computed functions.
In your situation, since selectedLabel and toolbartitle shares the same value, it is much better to simply bind them to the same property.
Also, attribute names that are declaratively passed in (through the element tag) need to be serialized, so selectedLabel becomes selected-label.
<body>
...
<template id="tpl" is="dom-bind">
<my-navigation selected-label="{{myLabel}}" id="my_navigation"></my-navigation>
<my-scaffold toolbartitle="{{myLabel}}" id="my_scaffold"></my-scaffold>
</template>
<script>
...
window.addEventListener("WebComponentsReady", function (e) {
document.querySelector("#tpl").myLabel = "Home";
...
});
...
</script>
</body>
There is probably a better way to do that, but you can try this:
<body>
<template id="app" is="dom-bind">
<my-navigation selectedLabel="Home" id="my_navigation"></my-navigation>
<my-scaffold toolbartitle="{{ selectedLabel }}" id="my_scaffold"></my-scaffold>
</template>
<script>
var app = document.querySelector('#app');
app.addEventListener('template-bound', function () {
console.log('Our app is ready to rock!');
});
window.addEventListener('WebComponentsReady', function () {
document.querySelector('body').removeAttribute('unresolved');
var my-navigation = document.querySelector('my-navigation');
// This will add the variable to the 'app' context (template)
app.selectedLabel = my-navigation.selectedLabel;
});
</script>
</body>

Custom filter not working in objects

How to make my custom filter work using bind?
Not Working Example:
JSON:
{ "name": "Adrian" }
HTML:
<template bind="{{user}}">
<p>{{name | filterName}}</p>
</template>
But it works normally when i use repeat.
Working Example:
JSON:
[
{ "name": "Adrian 1" },
{ "name": "Adrian 2" }
]
HTML:
<template repeat="{{user in users}}">
<p>{{user.name | filterName}}</p>
</template>
If you had defined filterName as a function under the elements's prototype...
Polymer('my-element', {
filterName: function(value){
return value.toUpperCase()
}
});
When we do
<template>
{{ user.name | filterName }}
<template>
you have access to your element and its properties 'user', 'users' and the filterName callback.
When you do
<template>
<template bind="{{user}}">
{{name | filterName}}
</template>
</template>
Your outer template has access to user and filterName.
But your inner template is now bound to see only the user object. Your scope is limited to user now. This is a special case when you use bind.
More info here... https://github.com/PolymerLabs/polymer-patterns/blob/master/snippets/basics/using-bind-to-create-a-single-template-instance.html
Nevertheless, there are options for you:
1- Less than ideal -> add the callback as a property in your object. Your model now is responsible for dom transformations. Sucks!
2- If you were to reuse the filter you can turn it into a global expression
PolymerExpressions.prototype.filterName = function (value) {
return value.toUpperCase();
};
And now you can use anywhere.