In Polymer I am creating some <app-route> elements in a <dom-repeat> as follows:
<template is="dom-repeat" items="{{myItems}}">
<app-route route="[[_route]]"
pattern="/view-{{index}}/:data"
data="{{_routeData}}"
active="{{_routeActive}}">
</app-route>
</template>
I'd like to use {{index}} within the data and active attribute values to create a dynamic binding property name such as {{_route{{index}}Data}} i.e evaluating {{index}} when creating the binding name. This would mean that they are unique for each route.
Is it possible to do this in Polymer? If not are there any alternative approaches?
Related
At first, i know, there are many questions about iron-list. But mostly about editing items and not whole template inside iron-list..
My code is really extremely complicated and posting it is pointless. I am working on data-tables which are using iron-list. I have element called diamond-listing and inside this diamond-listing i have iron-list.
You can image this like: Parent element define <template> with some content inside it, and child element (diamond-listing) will render this template as a table
Of course diamond-listing is used multiple times in my application and always with different template. For example: page users have columns with userID, userName etc.. and on page stations there are columns stationID, address etc.. with different number of columns. Every pagea has it's own <template> which i am trying to propagate to diamond-listing. For example:
<diamond-listing as="user" id="permissionsTable" type="pagination" pagination-items-per-page="6" header-data="{{headerData}}" address="/user/" loading="{{loading}}">
<div id="test" slot="content">
<template>
<div class="diamond-row" on-tap="_openUrl" info$="/user/[[user.id]]">
<diamond-item text="{{user.username}}"></diamond-item>
<diamond-item text="{{user.partner.name}}"></diamond-item>
</div>
</template>
</div>
</diamond-listing>
What i managed to do is to make it work in shadow dom using <slot> and simply rewrite <template> inside <iron-list>, but here we are.. For example using Firefox, which doesn't support webcomponents, there isn't <template> as a child of <iron-list> (because there is no shadow-dom) so there is no way how to update <template> and render iron-list.
What i tried:
1) Find template inside iron-list and use removeChild and appendChild functions.
var test = this.querySelector("#test template");
this.$$("#diamondList").removeChild(this.$$("#diamondList template"));
this.$$("#diamondList").appendChild(test);
Without success.
2) Define in HTML empty iron-list without any template inside it. And then in javascript add template dynamically. Without success. ( iron-list is crying it requires template)
3) Create dynamically iron-list using document.createElement
var test = this.querySelector("#test template");
var list = document.createElement("iron-list");
list.appendChild(test);
list.as = this.as;
list.items = [{"username":"test","partner":{"name":"Test partner","id":1}}];
list.id = "diamondList";
result: same as 2) ...
Is there a way, how to update template which is used to render all items in iron-list?
Or create iron-list with defined template inside JS ?
Or somehow do it with dom-repeat ? I won't have more than 10 items in listing, since it's fully pagination listing. ( this is propably simplest solution, but i don't know how to render <template> for every iteration
Here is one general answer, don't know if it will work for your case:
In Polymer, recommended way of manipulating the DOM is by manipulating the data, not by removeChild or appendChild.
For example,
if you have list of users as: var users_array = [....];
create the iron-list as:
<iron-list date="users_array">
<template>
...
<template>
</iron-list>
adding and removing elements in users_array will affect the iron-list
immediately.
Use a dom-if or use hidden inside the iron-list.
<iron-list items="[[items]]">
<template>
<template is="dom-if" if="[[item.isType1]]">
<!-- item1 -->
</template>
<template is="dom-if" if="[[item.isType2]]">
<!-- item2 -->
</template>
</template>
</iron-list>
I have the following nested dom-repeat:
<firebase-query
id="query"
path="[[path]]"
data="{{parentItems}}"
app-name="myApp">
</firebase-query>
<template is="dom-repeat"
items="{{parentItems}}"
as="parentItem">
<template is="dom-repeat" items="{{_toArray(parentItem)}}">
<div>{{item.details}} </div>
</template>
</template>
When items are added/removed from parentItems, the nested child dom-repeat template is not re-rendering i.e. _toArray() is not called. Is this behaviour expected? How do I ensure that when parentItems changes, the nested template will also be updated? Thanks.
I don't have the details of how you add something in the parentItems property, but i assume you do something like this
this.parentItems.push(something)
Polymer won't see the array change in that case, try to use the polymer push instead,
this.push('parentItems', something)
It will push it in the array, and notify polymer binding to update the view.
I was looking at dom-repeaters with the template tag. So i was going to walk an array. I wanted to then walk the properties of the object itself.
I didnt see anything online though. I was thinking of something like
<template is="dom-repeat" items="{{data}}" as="row">
<template is="dom-repeat" items="{{row}}" as="prop">
<div>{{prop}}</div>
</template>
</tempalate>
but the console throws one of those terrible stack traces about null not having the method "_badUpgrade". Maybe there is better documentation for 1.0 Polymer as to repeating over a dynamic object?
My end state is to create a datagrid allowing dynamic headers and dynamic data.... so the keys of the headers have to be a subset of the data properties so the correct items are assigned under the correct columns etc
Say I have two separate lists of polymorphic objects: Shape -> Circle and Shape -> Rectangle. Shape contains the properties "name" and "description", while Circle contains the properties "center" and "radius" and rectangle contains "length" and "width" properties. I'd like to have a single Polymer component, "shape-list", that would be able to handle display of either the list of Circles or list of Rectangles and display the specific properties of each type in the list.
"shape-list"'s template might look something like so:
<template>
<ul>
<template is="dom-repeat" items="[[shapes]]" as="shape">
<li>
<shape-entry shape="[[shape]]">
<!-- The user of shape-list knows whether we want to display
Rectangles or Circles. We want to customize the display
of each shape-entry with information specific to each
shape by using some sort of prototype element supplied
to the shape-list tag. -->
<content select="..."></content>
</shape-entry>
</li>
</template>
</ul>
</template>
And "shape-entry"'s template would look something like so:
<template>
Name: <span>[[shape.name]]</span>
Description: <span>[[shape.description]]</span>
<!-- Ideally we would take the passed-in prototype element and
stamp it out here. -->
<content select="...?"></content>
</template>
Further, we would have templates for "shape-circle" and "shape-rect":
shape-circle:
<template>
Center: <span>[[shape.center]]</span>
Radius: <span>[[shape.radius]]</span>
</template>
shape-rect:
<template>
Length: <span>[[shape.length]]</span>
Width: <span>[[shape.width]]</span>
</template>
The usage would ideally be something like the following:
I can see two ways of accomplishing the above:
Not using "content" tags, but instead setting a property on the shape-list and shape-entry elements to the actual prototype object reference or name of the specific shape, then having some magic JavaScript that creates an instance of that specific shape element based on that property and manually wiring all of the data binding together. This yields additional complexity to assemble the elements and data binding.
Replicate "shape-list" and "shape-entry" into "rect-list", "circle-list" and "rect-entry", "circle-entry", and share styles and behaviors between the subtypes. This results in some code duplication.
Is there a better way of accomplishing the above? I'd (ideally) prefer an entirely declarative approach!
You could have a shape-list component that uses an "if" template to display the proper shape component (rect-entry, circle-entry ). Each shape entry should declare a shared behavior, e.g ShapeBehavior that has all the shared shape behavior to avoid duplicity.
.. inside the dom-repeat
<template is="dom-if" if="{{_isRect(item)}}" >
<rect-entry shape={{item}} ></rect-entry>
</template>
<template is="dom-if" if="{{_isCircle(item)}}" >
<circle-entry shape={{item}} ></circle-entry>
</template>
If you want to dynamically pass the element that should be used , then a programatically solution is needed.
I would like to bind attr and attr1 in the following example. These two parameters do not depend on data (other attributes do). When using the binding this way, there is only one shared data object between all 'rows'. I want only the two components of one iteration to be bound together.
<template repeat"{{data in dataList}}">
<component1 attr="{{binding}}" />
<component2 attr2="{{binding}}" />
</template>
My first idea was to bind the attributes to an variable of the data object:
<template repeat"{{data in dataList}}">
<component1 attr="{{data.binding}}" />
<component2 attr2="{{data.binding}}" />
</template>
This solution on the other hand is really ugly, because the model object get's view-only data attached. Because the model lives normally longer than the components, this could cause a huge overhead. Another problem is serialization, which could fail because of the attached data.
Is there any elegant solution? The only one I imagined so far is to wrap the data objects before iterating over the data set. This approach on the other hand would probably make problems with model updates...
Naive thought: Shouldn't be the scope of a variable that is only used inside of a template restricted to this template? In the special case of the repeat template furthermore to one iteration?
You might type-suggest your binding variable being an Object and use it like:
<polymer-element name="my-element" attributes="dataList">
<template>
<ul>
<template repeat="{{d in dataList}}">
<li>
{{d}} ⇒ {{binding[d]}} <!-- Since type-suggested, it works -->
</li>
</template>
</ul>
</template>
<script>
Polymer({
dataList: ['navy', 'maroon'],
binding: {} /* it’s necessary to type-suggest var for Polymer */
});
</script>
</polymer-element>
Please be aware that the snippet above expects different items in dataList. Live preview: http://plnkr.co/edit/ez36BVUPCKW8xRSkGxOM?p=preview
Naive thought: Shouldn't be the scope of a variable that is only used inside of a template restricted to this template? In the special case of the repeat template furthermore to one iteration?
This sounds impossible for me, because (besides that this will overcomplicate the implementation) sometimes one wants to bind the variable in nested template:
<template repeat="{{a in lst}}">
{{bound_here}}
<template id="nested">
{{bound_here}}
...
With what you suggested the binding above becomes impossible.