Polymer 1.0 data binding options for accessing lists - polymer

In Polymer 1.0, is it possible to do:
{{ object in house.animals }}
where house.animals is a list? In the documentation, I found only simple examples in the binding, like {{ animals }}.

It looks like you're trying to change the name of the iterator to "object", which can be done by setting the <dom-repeat>.as property (i.e., as="object").
And yes, you can bind <dom-repeat>.items to a subproperty of an object as long as the subproperty is an Array.
<template is="dom-repeat" items="{{house.animals}}" as="{{object}}">
<div>Type: {{object.type}}</div>
</template>
demo

Related

How to include dynamic properties in path name inside dom-repeat?

I am trying to bind the state of a checkbox to a specific nested subproperty of hostProperty. The checkboxes are generated inside a nested "dom-repeat" template (iterating through innerObj per outerObj), and the desired subproperty of hostProperty is relative to subproperties of the other objects, i.e. it is of the form hostProperty[outerObj.name][innerObj.name].
I have been unable to figure out the correct path name for the subproperty.
I have tried the following and all have failed:
- hostProperty.outerObj.name.innerObj.name (likely looks for hostProperty.outerObj.name which is undefined)
- ['hostProperty', outerObj.name, innerObj.name] (based on the documentation for specifying paths)
- hostProperty[outerObj.name][innerObj.name]
- hostProperty.outerObj['name'].innerObj['name']
<template is="dom-repeat" items="[[outerObj_arr]]" as="outerObj">
<tr>
<th scope="row">[[outerObj.name]]</th>
<template is="dom-repeat" items="[[innerObj_arr]]" as="innerObj">
<!-- broken path name below -->
<td><paper-checkbox checked="[[hostProperty.outerObj.name.innerObj.name]]"></paper-checkbox></td>
</template>
</tr>
</template>
What you are trying to do is impossible from the html template.
To get this working, you need to use a helper method, eg:
<td><paper-checkbox checked="[[_getChecked(hostProperty, outerObj.name, innerObj.name)]]"></paper-checkbox></td>
And then in js:
_getChecked(list, key1, key2) {
return list[key1][key2];
}

How to reference a polymer component from auto-binding template?

How to reference the ts component from a binding annotation in an auto-binding template, as in {{ts.value}} shown below:
<template is="dom-bind">
<tri-state id='ts' value="open"></tri-state>
Value: {{ts.value}}
</template>
Figured out how to do this. Just imagine that the auto-binding template has a property called x (for example) and bind both things to x like this:
<template is="dom-bind">
<tri-state value="{{x}}"></tri-state>
Value: {{x}}
</template>

Two-Way Binding Across Components in Polymer

I have a Polymer app that has some nested components. I'm trying to share a property value across the components. My thought was that I could do this with data-binding. However, I have been unsuccessful in my attempt, which can be seen in this Plunkr. The relevant code (I think) is here:
<neon-animated-pages selected="[[selectedPageIndex]]" style="height:100%;">
<view-1 is-enabled="{{ isEnabled }}"></view-1>
<view-2 is-enabled="{{ isEnabled }}"></view-2>
</neon-animated-pages>
Each view has a paper-toggle-button. If the toggle button is set in one view, I want that same value to appear in the other view. Yet, that is not what's happening. It's like each view is using it's own isEnabled value. As the Plunkr shows, I've done the following:
Created a property called isEnabled in each view ("view-1.html" and "view-2.html").
Created a property called isEnabled in the hosting component ("shell.html")
Used two-way binding via the {{ }} curly-brace syntax.
What am I doing wrong? Why isn't the isEnabled value set in one view propogating to the other?
Thank you!
You should set notify to true in the definition of the isEnabled property in you views. This is needed for two-way data-binding (docs).
First: Name your element files the way you name your elements. Change shell to app-shell in your directory.
Second: What user Maria said, just declare a notify: true property to each element you want to be able to databind, like this:
<dom-module id="view-1">
<template>
<h2>View 1</h2>
<paper-toggle-button checked="{{ isEnabled }}">Is Enabled?</paper-toggle-button>
</template>
<script>
Polymer({
is: 'view-1',
properties: {
isEnabled: {
type: Boolean,
value: false,
notify: true
}
}
});
</script>
</dom-module>
Do the same for the view-2 property.
Here is your plunkr with working two-way data binding:
http://plnkr.co/edit/YhjE02O14YGCErXu9Vtq
Hope it helps you.

Polymer 1.0: Conditional Flow statements

Can I do something like the following, in Polymer 1.0:
<template is="dom-bind">
<template is="dom-if" if="{{ messagetype=='chat' }}">
<p>{{message.text}}</p>
</template>
<template is="dom-if" if="{{ messagetype=='location' }}">
<p>{{message.latitude}} , {{message.longitude}}</p>
</template>
</template>
i.e make a decision based on messagetype binding and write nothing else in Polymer() function
Expression syntax in Polymer 1.0 is very limited.
You can access fields (or propeeties) and functions.
The expression can use ! for not and . for . for array index and object property access.
For everything esle create a function that returns the computed result.
See also https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#expressions-in-binding-annotations
For your example you could create a function like
function: isEqual(a, b) {
return a == b;
}
and use it in the binding like
<template is="dom-if" if="{{isEqual(messagetype, 'chat')}}">
This is not a good use of dom-if statements. You are better off creating a function that computes what text to put into the p tag and moving the conditional logic into there.
Something along the lines of this:
<template is="dom-bind">
<p>[[computeMessageValue(message, messagetype)]]</p>
</template>
With the following computing function:
computeMessageValue: function (message, messagetype) {
if (messagetype === 'chat') {
return message.text;
} else if (messagetype === 'location') {
return message.latitude + ' , ' + message.longitude;
}
}
Using the dom-if approach is slower, harder to write tests for and gets very messy very quick as you add in new message types.

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>