Polymer: Access dynamically created node of dynamically created custom element - polymer

While updating my polymer project from 1.x to 2.0 I encountered this problem
I am wrapping one of my custom elements in dom-repeat like this
Host
<dom-repeat items="{{customer.hubs}}" as="item">
<template>
<paper-card elevation="2" class="hubCard">
<div style="font-size: 25px;font-weight: bold;line-height: 48px">HUB [[printIndex(customer.hubs,index)]]</div>
<hub-info hub="{{item}}" isloading="{{isloading}}" refresh-customer="[[refreshCustomer]]"/>
</paper-card>
</template>
</dom-repeat>
part of the code of custom element is like below
Custom element
<div class="blueButton" id="debugTab" style="padding-top: 10px">
<dom-if if="{{displayDebugger}}">
<template>
<div class="headButton" on-click="toggleDebugger" id="debuggerTab">
<span>Debugger</span>
<span style="position: absolute;right: 2%">
<!--<i id="downArrow4" class="material-icons fa-arrow-down">keyboard_arrow_down</i>-->
<iron-icon id="downArrow4" icon="icons:arrow-drop-down"></iron-icon>
</span>
</div>
</template>
</dom-if>
<iron-collapse id="collapseDebugger" >
<hub-debugger hub-id="{{hub.hubId}}" isloading="{{isloading}}"></hub-debugger>
</iron-collapse>
</div>
Problem
First i tried to access iron-collapse as
this.$.collapseDebugger but i couldn't ,as i thought the custom elemrnt hub-info is inside dom-repeat i used this.shadowRoot.querySelector('#collapseDebugger') and accessed it.
Again i tried to access iron-icon (which is again dynamically created inside dom-if) as this.shadowRoot.querySelector('#downArrow4') but i am unable to access it.
How to access a dynamic node inside dynamic element?
What if there is nesting of dynamic creations?

The this.shadowRoot.querySelector(selector) syntax should work.
Is the conditional template actually rendered? Do you import polymer/lib/elements/dom-if.html in your custom element? This is needed, if you otherwise only import polymer/polymer-element.html.

Related

Why is polymer's iron-selector not working for me?

I am trying to use iron-selector so that I can then dynamically change the main element on my webpage using iron-pages. The code is as follows:
<iron-selector selected='{{choice}}' attr-for-selected='option'>
<div option='home'>Homepage</a>
<div option='list'>List</a>
<div option='delete'>Delete items</a>
</iron-selector>
<h1>Your choice: {{choice}}</h1>
Nothing happens, the divs aren't clickable. I don't get any errors in the console.

Polymer 2.0 too many ifs

I'm looking for a better optimized solution to have too many if's in Polymer 2.0. For example i'm building a table object, where each cell can be text, buttons, links, objects, ect. I want the user to be able to enter a 2D array and have the Polymer 2.0 object be able to pick which markup to use. My current solution (below) simple has several if statements, but this means that every cell if going to call each statement. Is there a a better way to handle this?
<template is="dom-if" if="[[matchCellType(cell, 'button')]]">
<UI-Button id='[[cell.button.ID]]' class$='[[cell.button.class]]'>[[cell.button.text]]</UI-Button>
</template>
<template is="dom-if" if="[[matchCellType(cell, 'object')]]">
<span class="object-toggle"></span>[[cell.title]]
<div class="properties">
<template is="dom-repeat" items="[[getProps(cell)]]">
<div class="properties_row"><div class="properties_cell"><b>[[item.title]]:</b></div><div style="display: table-cell">[[item.val]]</div></div>
</template>
</div>
</template>
<template is="dom-if" if="[[matchCellType(cell, 'link')]]">
<a target="_blank" href='[[cell.link.href]]'>[[cell.link.text]]</a>
</template>
<template is="dom-if" if="[[matchCellType(cell, 'cell')]]">
[[cell]]
</template>
<template is="dom-if" if="[[matchCellType(cell, 'textArea')]]">
<ui-text-area rows="[[cell.textArea.rows]]" cols="[[cell.textArea.cols]]" id='[[cell.textArea.id]]' class$='[[cell.textArea.class]]' text= [[cell.textArea.text]]></ui-text-area>
</template>
Lots of calls to matchCellType don't harm if it isn't a costly computation (if it were, you could update a property in an observer and test on the property instead)
Factor out the series of ifs into a component so you don't clutter up your table
As an alternative to using dom-ifs, compute an attribute or style class from the cell, render all elements always, and use CSS to have only the matching elements be visible. This produces much more DOM elements, but may still be more performant because browsers handle hidden or display:none elements very efficiently
Instead of stamping with several dom-ifs, you could create and remove nodes imperatively

Prevent polymer from setting sub-elements class to style-scope

I'm having some trouble migrating to Polymer 1.0
My main problem is that the classes "style-scope" and "my-element" are being applied to every child node in the element. This is not a problem when using something like this:
<paper-dialog modal class="vertical layout">
<div class="top">
<div class="green">{{format(inputtext)}}</div>
It just changes their classes to "top style-scope my-element" and "green style-scope my-element" respectively and everything works ok.
But right now on Polymer 1.0 I can't bind a classname to a property, so I have to compute it with something like this:
<template is="dom-repeat" items="{{ item-list }}" as="item">
<span class="{{setitemclass(item)}}" on-click="itemClicked" role="button" >{{item}}</span>
</template>
setitemclass: function (item) {
return 'itnumb' + item;
}
As the element is created every span created goes through the setitemclass function and it returns what it should (something like 'itnumb1', 'itnumb2' and so on), but when it finishes, the class appears as "style-scope my-element" for every span, with no sigh of the 'itnumb#' bit anywhere.
I just don't know how to approach this, since binding has changed quite a bit in my eyes.
Thanks!
In order to bind to an attribute that does not match to a respective JS property of that element (e.g. class, href, data-*), you should use $= rather than plain =.
<span class$="{{setitemclass(item)}}" on-click="itemClicked" role="button">{{item}}</span>
Source: https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#attribute-binding

How to loop through nested Firebase keys in Polymer

So, I have a Polymer project that is saving to Firebase. My data looks like this:
What I'm trying to do is loop through the teams property in the data. Considering Polymer only loops through Arrays right now, this is proving to be pretty challenging (since Firebase preferably returns data as objects). So far, I can loop through the keys and get the teams, but can't get into the teams to loop through it. Here is my code:
<template repeat="{{key in keys}}">
<div class="tile">
<paper-shadow z="2" class="card" animated>
<div id="header" class="header"></div>
<div class="content">
<p>{{data[key]}}</p>
<span>{{team.club}}</span>
</div>
<footer horizontal layout>
<paper-button id="teamview" on-tap="{{viewTeam}}" flex>VIEW</paper-button>
<span flex></span>
<paper-button id="teamDelete" on-tap="{{deleteTeam}}">DELETE</paper-button>
<paper-button id="teamEdit" on-tap="{{editTeam}}">EDIT</paper-button>
</footer>
</paper-shadow>
</div>
</template>
I feel like I've tried almost every scenerio. Every time I try and loop one more level with repeat="{{team in key}}" it breaks. Seeing if maybe some one else has a better perspective on this? Thanks in advance!
You need to bind the data, id and keys like this I think.
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../firebase-element/firebase-element.html">
<!--
Element providing solution to displaying value from firebase.
##### Example
<firebase-repeat-element></firebase-repeat-element>
#element fb-repeat-element
#blurb Element providing solution to displaying value from firebase.
#status alpha
#homepage http://basicelements.github.io/firebase-repeat-element
-->
<polymer-element name="firebase-repeat-element" attributes="firebaseName">
<template>
<firebase-element location="https://{{firebaseName}}.firebaseio.com/members/{{id}}" data="{{data}}" keys="{{keys}}"></firebase-element>
<template repeat="{{id in keys}}">
<h2>{{data[id]['name']}}</h2>
<img src="{{data[id]['image']}}">
</template>
</template>
<script>
Polymer({
});
</script>
</polymer-element>
Be free to fork it #https://gist.github.com/ed2ba06d5a16d11381d9.git
So, the way I found out needs more in-depth explaining regarding Polymer and Firebase. First off, when you enter your location attribute in the firebase-element, whenever you are sourcing your data and keys, it is specifically with that location - not your data as a whole.
Therefore, the problem I was having was rooted in my location attribute. Once I changed my location to specify the exact nested level I wanted to push and source data from - all was well. The end code looked like this:
<firebase-element id="fbase"
location="https://volleyball-app.firebaseio.com/{{user.uid}}/userTeams"
data="{{userTeams}}" keys="{{keys}}" dataReady="{{userReady}}">
</firebase-element>
<template repeat="{{key in keys}}">
<div class="content">
<p>{{userTeams[key]['team']}}</p>
<span>{{userTeams[key]['club']}}</span>
</div>
</template>
What this is doing is repeating through all the keys in the <firebase-element id="fbase"
location="https://volleyball-app.firebaseio.com/{{user.uid}}/userTeams location (nothing more). From there I'm grabbing the team property in each key.

Extend polymer element - access parent content

I have the following polymer:
<polymer-element name="popup-element" attributes="popupStyle">
<template>
<div class="popup" id="popup" style="{{popupStyle}}">
<div class="closebutton"></div>
<content select=".title"></content>
<br /><br />
<content></content>
</div>
</template>
<script type="text/javascript">
Polymer('popup-element');
</script>
</polymer-element>
Now I want to extend it in another polymer:
<polymer-element name="newfolder-element" attributes="popupStyle" extends="popup-element">
<template>
<shadow>
<span class="title">Utwórz nowy folder</span>
<input type="text" class="ginput" style="width: 350px; padding: 5px;" placeholder="Nowy katalog" />
<br />
<button class="action blue"><span class="label">Utwórz</span></button>
<button class="action red" id="cancelBtn" on-click="{{closePopup}}"><span class="label">Anuluj</span></button>
<content></content>
</shadow>
</template>
<script>
Polymer('newfolder-element');
</script>
</polymer-element>
Why content between <shadow> and </shadow> doesn't appear. I want to place content of <shadow> ... </shadow> (child element) to <content></content> of parent element. How to make it working ?
This used to be supported, but due to implementation concerns, it was removed. It will most likely be added in a future revision to the Shadow DOM spec.
Update: Here's a possible interim solution to this problem.
This almost makes the extends feature useless for template inheritance! I take a look at all the core-elements and paper-elements, rarely are they reusing templates from their base element. To get around this limitation I have to use a preprocessor like jade to mix-in partials. But if polymer or the spec can support this, it will be much more convenient. A little bit frustrating that I need to spend so much time just to fix something that should be there.