Polymer elements: to nest or not to nest? - polymer

We're developing a data visualization library using Polymer, and I must say I'm impressed with what Polymer lets you do. We do have a question, though...
First: here's an example snippet of code showing a data visualization:
<template is="auto-binding">
<our-loaddata url="data/data.csv" data="{{data}}"></our-loaddata>
<our-scatterplot data="{{data}}"></our-scatterplot>
<our-barchart data="{{data}}" dimension="weight"></our-barchart>
<our-histogram data="{{data}}" dimension="weight" binSize=10></our-histogram>
</template>
The our-loaddata loads the dataset from a file data/data.csv, performs some transformations (e.g. converting strings to numbers, calculating distributions, ...) and makes it available through {{data}} to the our-scatterplot, our-barchart and our-histogram. However, I'm not completely satisfied with the setup. Conceptually, the our-loaddata is different from the other three, and should precede them. As an alternative, we have also tried the following (renaming loaddata to app and nesting all visuals within the app):
<template is="auto-binding">
<our-app url="data/data.csv" data="{{data}}">
<our-scatterplot data="{{data}}"></our-scatterplot>
<our-barchart data="{{data}}" dimension="weight"></our-barchart>
<our-histogram data="{{data}}" dimension="weight" binSize=10></our-histogram>
</our-app>
</template>
Although this also works, we noticed that it doesn't matter if we close the </our-app> element before or after all the visual elements.
What would be the most canonical way to handle this in Polymer? What is the difference between the approaches that I showed here?

you could use the conditional template to check if data is present and then send the other elements to the dom if true or show a loader if false. (careful getting to used to this i don't think it is currently in 0.8. sad IMO i <3 it)
<template is="auto-binding">
<our-loaddata url="data/data.csv" data="{{data}}"></our-loaddata>
<template if="{{data}}">
<our-scatterplot data="{{data}}"></our-scatterplot>
<our-barchart data="{{data}}" dimension="weight"></our-barchart>
<our-histogram data="{{data}}" dimension="weight" binSize=10></our-histogram>
</template>
<template if="{{!data}}">
<pretty-loadingscreen></pretty-loadingscreen>
</template>
</template>
the would give you seperation of elements you were looking for.

Related

is it possible nest/inner dom-if where the second dom-if depends on value oberseved from the first dom-if block

I read carefully these threads
Polymer 1 nested dom-if within dom-repeat not updating when data changes
how to dynamically append an element to dom-if in Polymer?
How to access content of dom-if inside a custom element?
that may have some relation with my question but I didn't manage find any clue if I can do what I want and how.
In my company, there are several flows, each one for each business flow and each step of the flow is a screen coded as a Polymer 1 web component. All them are warraped in a root Polymer component which defines the route.
A simple exemple would be:
my-root-component:
<dom-module id="my-root-component">
<template>
<first-obrigatiory-page which-route={aValueReturnedFromFirstComponent}></first-obrigatiory-page>
<template is="dom-if" if="[[_isTrueFunction(aValueReturnedFromFirstComponent)]]" restamp>
<second-page which-sub-route={aValueReturnedFromSecondComponent}></second-page>
<template is="dom-if" if="[[_isTrueFunction(aValueReturnedFromSecondComponentComponent)]]" restamp>
<third-page ></third-page>
</template>
</template>
</template>
<script>
Polymer({
is: 'my-root-component',
behaviors: [doesntMatterHere],
properties: {
The first dom-if works as expected but the second seems not be taken in account and my third-page component is never showed.
I checked and the equivalent for _isTrueFunction(aValueReturnedFromSecondComponentComponent) is returning true.
Does aValueReturnedFromFirstComponent really return anything, because you should declare the attribute as which-route="{{aValueReturnedFromFirstComponent}}" instead of using simple { }.
Does the whichRoute (note the camelCase) property in the first-obrigatiory-page element have the notify: true property so the variable actually sends back the updated value?
I usually set observers on variables whenever dom-ifs don't update so I can see if they really change or not, and then set the variables myself through the console with document.querySelector('my-root-component').set('aValueReturnedFromFirstComponent', true) so I can see that the dom-if really updates.
A workaround could be to use events, but what you've done should work.

dynamically edit template of iron-list

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>

template dom-repeat for an Object?

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

How to share variables with siblings?

I'm very new to Polymer, so please don't hold back any information!
I have a basic webpage with a standard format, and I'm trying to figure out how I can expose the #nav component variable currentSelection with the #main component, which depends on the selection for switching out the correct template:
head
body
div#nav
div#main
div#footer
I understand the encapsulation aspect of Polymer, but I lack an understanding of the glue, eventing system, and different instantiation patterns for the dynamic HTML, especially since Polymer 0.5 is deprecated.
Does <template is="dom-bind"> actually render as if it weren't a <template>? I'm thinking to wrap the whole site in one, but I'm not sure that's a good idea.
Why not make your #nav and #main custom components? That way you could bind to currentSelection like so:
<my-nav current-selection="{{currentSelection}}"></my-nav>
<my-main current-selection="[[currentSelection]]"></my-main>
The dom-bind template is necessary to make bindings work between elements in the main document (i.e index.html), so you could either use dom-bind:
<template is="dom-bind">
<my-nav current-selection="{{currentSelection}}"></my-nav>
<my-main current-selection="[[currentSelection]]"></my-main>
<my-footer></my-footer>
</template>
Or you could put all of your elements in another custom component such as my-app in which the bindings will work:
index.html
<body>
<my-app></my-app>
</body>
my-app.html
<template>
<my-nav current-selection="{{currentSelection}}"></my-nav>
<my-main current-selection="[[currentSelection]]"></my-main>
<my-footer></my-footer>
</template>

Bind parameters of two polymer components inside repeat template

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.