Polymer dom-if: how do I implement a negative condition? - polymer

I have a Polymer element that uses <template is="dom-if"... to provide different HTML content depending on a condition.
Polymer dom-if has no else condition, so needs a negative if condition to simulate it.
Something like this:
<link href="https://polygit.org/components/polymer/polymer.html" rel="import">
<dom-module id="test-thing">
<template>
<template is="dom-if" if="{{title}}" restamp>
<b>[[title]]</b>
</template>
<template is="dom-if" if="{{!title}}" restamp>
<i>no title</i>
</template>
</template>
<script>
Polymer({
is: 'test-thing',
properties: {
title: String
}
});
</script>
</dom-module>
<div>
With negative condition:
<test-thing></test-thing>
</div>
<div>
With positive condition:
<test-thing title="Has Title"></test-thing>
</div>
Only that doesn't work - the negative condition never passes.
How should this be implemented?

You must use a default empty value for your title property:
title:{type: String,value:''}
Like so:
<link href="https://polygit.org/components/polymer/polymer.html" rel="import">
<dom-module id="test-thing">
<template>
<template is="dom-if" if="{{title}}" restamp>
<b>[[title]]</b>
</template>
<template is="dom-if" if="{{!title}}" restamp>
<i>no title</i>
</template>
</template>
<script>
Polymer({
is: 'test-thing',
properties: {
title: {type: String,value:''}
}
});
</script>
</dom-module>
<div>
With negative condition:
<test-thing></test-thing>
</div>
<div>
With positive condition:
<test-thing title="Has Title"></test-thing>
</div>

Related

Subset hyphenated JSON element in Polymer data binding

Consider the following JSON:
{"EMD-4091":["EMD-4084","EMD-4090"]}
which is the result of a fictitious iron-ajax call as follows:
<iron-ajax
auto
url="http://me.com/get/EMD-4091"
handle-as="json"
last-response="{{my_data}}">
</iron-ajax>
Suppose I need to refer to the inner array, say, in a dom-repeat: how would I refer to 'EMD-4091' in a data binding? e.g.
<template is="dom-repeat" items="{{my_data????}}> <!-- what should this be?-->
<p>{{item}}</p>
</template>
If the data wasn't hyphenated this is a trivial task. The hyphen is the challenge I'm facing.
P
The data binding can still parse the hyphenated key without a problem, so your binding would be:
items="{{my_data.EMD-4091}}"
HTMLImports.whenReady(() => {
"use strict";
Polymer({
is: 'x-foo',
properties : {
my_data: {
type: Array,
value: () => ({"EMD-4091":["EMD-4084","EMD-4090"]})
}
}
});
});
<head>
<base href="https://polygit.org/polymer+1.7.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<template is="dom-repeat" items="[[my_data.EMD-4091]]">
<div>[[item]]</div>
</template>
</template>
</dom-module>
</body>
codepen

How to use dom-bind within test-fixture?

How can I use <template is="dom-bind"> within <test-fixture> with web-components-tester?
I have tried to use it Polymer 0.8 x-template way:
<test-fixture id="dom-bind-fixture">
<template is="dom-bind">
<h1>{{greeting}}</h2>
</template>
</test-fixture>
<script>
// ...
var bound = fixture('dom-bind-fixture', {greeting: 'ohai thurr'});
</script>
which naturally fails, as dom-bind does not have stamp method.
Then, I tried just stamping it out of native <template> element:
<test-fixture id="dom-bind-fixture">
<template>
<h1>outside dom-bind</h1>
<template is="dom-bind">
<h2>inside dom-bind</h2>
</template>
</template>
</test-fixture>
But in non-Chrome browsers this one stamps only outside dom-bind.
Is there a way to make it work, or is it just a blocking bug in web-components-tester/test-fixture/dom-bind?
Use dom-template, ie:
<test-fixture id="dom-bind-fixture">
<template is="dom-template">
<h1>{{greeting}}</h2>
</template>
</test-fixture>
<script>
// ...
var bound = fixture('dom-bind-fixture', {greeting: 'ohai thurr'});
</script>

Polymer: Passing properties to child element doesn't work

I'm trying to output data from a custom Polymer component <data-component> in an <iron-list> but nothing is shown when I open the page. It works when I pass an array of objects directly to the iron-list like <iron-list items='[{"name": "test1"}, {"name":"test2"}]' >
What am I doing wrong here and is the <template is="dom-bind" id="t"> mandatory?
index.html
<html>
<head>
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../data-component.html">
<link rel="import" href="../../iron-list/iron-list.html">
</head>
<body unresolved>
<template is="dom-bind" id="t">
<data-component>
<!--<iron-list items='[{"name": "test1"}, {"name":"test2"}]' > WORKS -->
<iron-list items="{{data}}" >
<template>
<div>
Name: <span>{{item.name}}</span>
</div>
</template>
</iron-list>
</data-component>
</template>
</body>
</html>
data-component.html
<link rel="import" href="../polymer/polymer.html">
<dom-module id="data-component">
<template>
<content></content>
</template>
</dom-module>
<script>
window.coolData = [
{"name": "Bob"},
{"name": "Tim"},
{"name": "Mike"}
];
Polymer({
is: 'data-component',
properties: {
data: {
value: window.coolData
}
}
});
</script>
I'm going to suggest an alternative answer to what I have already posted. If you want your data-component to always contain the iron-list then you can use this version here. However, if the content of the data-component should be more flexible use my other answer.
If you move the iron-list inside the data-component you can remove the dom-bind in your index.html.
data-component.html
<link rel="import" href="../polymer/polymer.html">
<dom-module id="data-component">
<template>
<iron-list items="{{data}}" >
<template>
<div>
Name: <span>{{item.name}}</span>
</div>
</template>
</iron-list>
</template>
</dom-module>
<script>
window.coolData = [
{"name": "Bob"},
{"name": "Tim"},
{"name": "Mike"}
];
Polymer({
is: 'data-component',
properties: {
data: {
type: Array,
value: window.coolData
}
}
});
</script>
index.html
<body unresolved>
<data-component></data-component>
</body>
You also have to add a data-binding to your data-component. Otherwise, the system does not know that data (in your iron-list) should refer to the data property in your custom element.
<data-component data="{{data}}">
<iron-list items="{{data}}" >
...
</iron-list>
</data-component>
The dom-bind is necessary if you want to have data-binding outside of a Polymer element, which seems to be the case here.
You should also make sure that the data property is configured to notify changes and that its type is set to Array.
Polymer({
is: 'data-component',
properties: {
data: {
type: Array,
value: window.coolData,
notify: true
}
}
});

Polymer iron-list dynamically adding items?

I'm trying to migrate some code from Polymer 0.5 to 1.x, this means moving from core-list to iron-list. However, I can not figure out an iron equivalent to how I was adding items to the core-list.
<core-list height="85">
<template>
<div class="{{ {selected: selected} | tokenList }}" style="padding:5px;"><paper-fab mini icon="arrow-forward" title="arrow-forward"></paper-fab> <!--{{index}}-->{{model.name}}</div>
</template>
</core-list>
which is called updated via...
document.querySelector('core-list').data = $.parseJSON('[{"name":"One"},{"name":"Two"}]');
Anyone have any suggestions?
Update : Jul-23-2015 12:20PM PST
#Zikes
Following the suggestion posted, I have the following.
<dom-module id="my-element">
<template>
<iron-list items="[[myItems]]" as="item">
<template>
<div>[[item.name]]</div>
</template>
</iron-list>
</template>
<script>
Polymer({
is:'my-element',
properties: {
myItems: Array
},
addItem: function(item) {
this.push('myItems', {name: item});
}
});
</script>
</dom-module>
If this is setup right, how would I go about calling the addItem method from elsewhere?
Update : Jul-23-2015 1:58PM PST
#Zikes
Following is my current code. While I can manipulate the array, values added to it in the ready or addItem method are not being displayed.
<dom-module id="fnord-element">
<template>
<iron-list items="[[myItems]]" as="item">
<template>
<div class="item">[[item.name]]</div>
</template>
</iron-list>
</template>
<script>
Polymer({
is:'fnord-element',
properties: {
myItems: {
type: Array,
notify: true
}
},
addItem: function(item) {
//this.push("myItems", {"name":item});
this.myItems=[{name:item}];
alert(this.myItems[0].name);
//alert(item);
},
ready: function() {
//alert('fnord');
this.myItems=[{name:"One"},{name:"Two"}];
}
});
</script>
</dom-module>
<fnord-element id="fnord"></fnord-element>
<paper-button raised onclick="document.querySelector('#fnord').addItem('John Doe');">Test</paper-button>
iron-list uses the items property to generate its items, similar to dom-repeat. What you can do is simply bind it to an Array in your component, like so:
<dom-module id="my-element>
<template>
<iron-list items="[[myItems]]">
<template>
<div>[[item]]</div>
</template>
</iron-list>
</template>
<script>
Polymer({
is:'my-element',
properties: {
myItems: Array
}
});
</script>
</dom-module>
Then, just follow the rules for modifying an Array property and you're all set!

Polymer Need some help building a url in iron-list item

I'm running into a similar problem as this question.
However, my case is a bit different and I can't seem to get it to work. I've been playing with it for a while an no luck so far.. I need href$="{{_getProject(item.project_id)}}" to be written as "webservices/api/projects/1" but the closest thing I can get is it outputting the item.project_id without being able to concatenate with it so just the 1. I've tried various things but below is what I have most recently. Does anyone have any ideas on how I can get this to work? I'm sure it's something I'm overlooking.
<template is="dom-bind">
<iron-ajax url="<?echo $url?>" last-response="{{data}}" auto></iron-ajax>
<iron-list items="[[data]]" as="item">
<template>
<div>
<div class="item">
<div class="pad">
<div class="primary">[[item.project_name]]</div>
<div class="secondary">Project Deadline:</div>
<div class="secondary">[[item.project_deadline]</div
<div class="secondary">Total Hours to date:</div>
<div class="secondary">[[item.project_total_hours</div>
<div class="secondary">[[item.project_id]]</div>
</div>
<a href$="{{_getProject(item.project_id)}}"><iron-icon icon="assignment"><iron-icon></a>
</div>
</div>
</template>
<script>
Polymer({
_getProject: function(url) {
return 'webservices/api/projects/' + url
}
});
</script>
</iron-list>
</template>
The Polymer({...}) call you have inside of your iron-list won't work as you expect (and it should actually show an error in the console), since you are not defining/can't define a custom element inside of iron-list but only a template that will be stamped.
There are two ways to achieve what you want.
Define a custom element that you use inside of the iron-list
<dom-module id="my-item">
<template>
<div class="item">
...
<a href$="{{_getProject(item.project_id)}}">...</a>
</div>
</template>
<script>
Polymer({
is: 'my-item',
properties: {
item: Object
},
_getProject: function(url) {
return 'webservices/api/projects/' + url
}
});
</script>
</dom-module>
<iron-list items="[[data]]" as="item">
<template>
<my-item item="[[item]]"></my-item>
</template>
</iron-list>
Define the _getProject function on your main template
<template is="dom-bind" id="app">
...
<iron-list items="[[data]]" as="item">
<template>
<div>
<div class="item">
...
<a href$="{{_getProject(item.project_id)}}">...</a>
</div>
</div>
</template>
</iron-list>
</template>
<script>
var app = document.getElementById('app');
app._getProject = function (url) {
return 'webservices/api/projects/' + url
}
</script>