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.
Related
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
I've recently started using the <template> tag for HTML that I process afterwards using a template library, e.g.
<template id="tmpl">
<div class="something">
{{title}}
</div>
</template>
...
<script>
var output = Mustache.render($('#tmpl').html(), {
link: 'abc',
title: 'abc'
});
</script>
However, I've come to realise this means I have a broken link (example.com/pages/{{link}}) in my HTML. This is a concern, as various crawlers might consider it invalid (in fact, the Google Search Console reports my homepage as having a broken link).
Is it valid to use <template> this way?
Is it better to put it in something like <script type="text/template"> instead (as seen on the handlebars.js website)?
The output variable does contain the HTML we would expect, i.e., the rendered template; however, your code does not write the contents of the output variable anywhere.
Here is a working example:
<template id="tmpl">
<div class="something">
{{title}}
</div>
</template>
<span id="output"></span>
<script>
var output = Mustache.render($('#tmpl').html(), {
link: 'abc',
title: 'abc'
});
$('#output').html(output);
</script>
Google has not properly crawled the test site I setup for this. However, when I asked GoogleBot to render my version of your code it displayed the link inside the template element, i.e., *{{title}}* and the rendered template link, i.e., *abc*. Even though Google says you have a broken link in the template element, you really don't when a user views it.
One possible way to get Google to quit indicating that you have a broken link is to surround your template tags with <!--googleoff: anchor--> ...templates... <!--googleon: anchor-->. These tags stop googlebot from indexing anchor tags contained within.
Example:
<!--googleoff: anchor-->
<template id="tmpl">
<div class="something">
{{title}}
</div>
</template>
<!--googleon: anchor-->
I'm using a conditional template to distribute content that is passed into the element. If the condition is true, it will show the first content element, otherwise the second. I noticed that when I update the condition the already distributed content is not updated. Once it is visible it will remain visible.
My first attempt looked like this:
<template is="dom-if" if="{{test}}">
<content select=".first">
</content>
</template>
<template is="dom-if" if="{{!test}}">
<content select=".second">
</content>
</template>
I noticed that it will work, if the content is wrapped in another element.
<template is="dom-if" if="{{test}}">
<div>
<content select=".first">
</content>
</div>
</template>
<template is="dom-if" if="{{!test}}">
<div>
<content select=".second">
</content>
</div>
</template>
I've created a plunker that demonstrates both cases.
Is there an explanation for this behaviour? Is it on purpose or a bug?
This is actually per design. Here`s what the Polymer team had to say on the issue on Github.
Hiding a <content> has no effect on the visibility of its distributed children (per spec), so your options are to wrap the content with a wrapper element that can be hidden (and will hide the distributed children), or use restamp which will pull the <content> out of the DOM all together.
It is slightly unintuitive that the restamp and non-restamp setups work differently, however it is a result of the non-restamp behavior which hides rather than destroying DOM as a performance optimization.
Our team is building our first polymer all in one page app and we kind of have to reverse engineer a neglected component of the project. We need to set the title for the title bar in the core-scaffolding. This is easy on simple pages by using JS, however some pages have conditional templates that show content and each require their own titles.
eg
<core-scaffolding>
<div id="title">Dynamic Title goes here</div>
<core-animated-pages transitions="cross-fade">
<section>
<div cross-fade>
<my-element>
<template if="{{condition1}}"></template>
Content 1
</template>
<template if="{{condition2}}"></template>
Content 2
</template>
<template if="{{condition3}}"></template>
Content 3
</template>
</my-element>
</div>
</section>
<section>
<div cross-fade></div>
</section>
</core-animated-pages>
I was going to add an attribute on the template elements to be able to pass a title value, however I don't know how to use JS to find out which template is the one that is conditionally rendered (active). I can't seem to find any documentation on this. Also I want to build something reusable (not with IDs) that can be used globally on any page.
Can anyone provide any suggestions?
Cheers,
david
i don't think i would use conditional template for this. if that condition changes a lot the content of the template will be added and removed from the dom every time it is changed. i think it would be better to use the hidden attribute or use databinding to change the text dynamically.
hidden attribute
<span hidden?="{{!condition1}}">Content 1</span>
<span hidden?="{{!condition2}}">Content 2</span>
<span hidden?="{{!condition2}}">Content 3</span>
databinding
<span>{{content}}</span>
then you can change the databind in javascript like normal.
if (condition1) {
this.content = 'Content 1';
}
I have just stepped into Polymer. At the moment I am trying to use more-route library to switch between elements. The polycast from Rob Dodson is here. The basic concept of declarative route is well understood and I can make it to work.
But my requirement is slightly different. I have created two elements:
<customer-list>
This prases a JSON string and displays a list of customers I have. Every JSON record is associated with a CustomerId.
<contact-info>
A JSON string is involved here as well which has a list of contact information each mapped up with a CustomerId.
I have an attribute (custid) set in my contact-info element, i.e. attributes="custid".
What I want is to click on a customer from customer-list element and invoke a route something like /customers/50. This 50 needs to be set in {{custid}} attribute of contact-info element. And finally based on this Customer Id, Polymer would parse and pick up the contact(s) from the JSON string. Once it gets it the following snippet:
<template repeat={{c in contacts}}></template>
would bind the list of contacts for Customer Id 50. I have no idea how to set an attribute value of another using route parameters. Seeking for expert help. I tried on Google but unfortunately could not find a suitable answer!
The following screenshot might help to understand what exactly I am looking for!
Thanks in advance.
EDIT:
Routes.HTML
<link rel="import" href="../bower_components/more-routing/more-routing.html"/>
<more-routing-config driver="hash"></more-routing-config>
<more-route name="home" path="/"></more-route>
<more-route name="customers" path="/customers">
<more-route name="customer-contact" path="/:custext"></more-route>
</more-route>
Index.html (core-menu)
<more-route-selector>
<core-menu selected="0">
<core-item label="Home" route="home">
</core-item>
<core-item label="Customers" route="customers">
</core-item>
</core-menu>
</more-route-selector>
Index.html (main section)
<more-route-selector selectedParams="{{params}}">
<core-pages>
<section route="home">
<h1>Home</h1>
<div>This is the home section</div>
</section>
<section route="customers">
<h1>Customers</h1>
<div>This is customers section</div>
</section>
</core-pages>
</more-route-selector>
Output (Screenshot)
Tested in both
Chrome (42.0.2311.135 m) and Firefox (37.0.2)
I think you'll want to bind to the selectedParams property of the more-routing element. I explain it a bit toward the end of the polycast: https://youtu.be/-67kb7poIT8?t=3m15s
Thanks to Polycast from Rob Dodson on YouTube, and answer from Ian McLeod in Google Group.
The code snippet looks like this:
Index.html
<section route="customer-detail">
<post-card>
<h2>Our branches</h2>
<div><customer-detail route="customer-detail" cname="{{params.cust}}"></customer-detail></div>
<footer>Bck to list</footer>
</post-card>
</section>
Customer-detail.html
<customer-detail>
<polymer-element name="customer-detail" attributes="cname fullname">
<template>
<link rel="stylesheet" href="customer-detail.css">
<template repeat="{{c in customers}}">
<template repeat="{{b in c.branches}}" if="{{c.cuname == cname}}">
<div class="single-customer-info">
<h1>{{b.branch}} (Code: {{b.code}})</h1>
<p>
{{b.address}}. Phone: {{b.phone}}<br/>
</p>
<h1>{{b.email}}</h1>
</div>
</template>
</template>
</template>
And finally the routes.html
<more-route name="customers" path="/customers">
<more-route name="customer-detail" path="/:cust"></more-route>
</more-route>
Hope this will help others.