Polymer 1.0 - How to bind html value - polymer

I have a list of items in which each item has a .content html value as following.
<template is="dom-repeat" items="{{entries}}">
<li><p class="paper-font-body2">{{item.title}}</p>
<div>{{item.content}}</div></li>
</template>
content field is somewhat like this
Hello <strong>Polymer</strong>
It shows in browser as plain text. How do I show it as safe html?
EDIT: this issue is raised, but it doesn't help me.

You could easily do:
<template is="dom-repeat" items="{{entries}}">
<li><p class="paper-font-body2">{{item.title}}</p>
<div inner-h-t-m-l="{{item.content}}"></div></li>
</template>
That's what I'm using, bearing in mind that XSS vulnerability is open.

You could try something like this:
<dom-module id="echo-html">
<template>
<span>{{html}}</span>
</template>
<script>
Polymer({
is: 'echo-html',
properties: {
html: {
type: String,
value: 'html'
}
},
ready: function() {
this.innerHTML = this.html;
}
});
</script>
</dom-module>
and call it like that I guess:
<div><echo-html html="{{item.content}}"></echo-html></div>

Related

nesting elements and dynamic content inside dom-repeat - Polymer 1.0

I have a <parent> element, a <tabs> element inside it with an arbitrary number of tabs (purely for hiding/showing logic in the UI), and a <child> element inside each <tab>. Right now I have the following working:
<!-- inside parent.html: -->
<tabs></tabs>
<!-- inside tabs.html: -->
<template is="dom-repeat" items="{{tabs}}" as="tab" index-as="item_no">
<section>
<child id="element-{{tab.index}}"></child>
</section>
</template>
Only <parent> knows how many instances of <child> there needs to be (<tabs> merely receives an array from <parent> and iterates over it.
Is there a way to not hard-code <child> inside the local DOM of <tabs>? Thinking of using <content> and light DOM but no idea where to even start. Would it be a promising route to take?
Desired state:
<!-- inside parent.html: -->
<tabs>
// somehow specify base content to be rendered in each tab
</tabs>
<!-- inside tabs.html: -->
<template is="dom-repeat" items="{{tabs}}" as="tab" index-as="item_no">
<section>
// somehow inject stuff from parent element, perhaps via <content>?
</section>
</template>
This is my interpretation of your question, so I am not really sure if it will be OK with you. If I misunderstood you, please drop a comment and I will gladly update my answer.
I have come up with a simple element composition, requiring no dom-repeat or manual template stamping. The solution consists of two custom elements, namely my-parent and my-child.
The definitions for both custom elements are the following:
<dom-module id="my-parent">
<template>
<tabs>
<content></content>
</tabs>
</template>
<script>
Polymer({
is: 'my-parent',
});
</script>
</dom-module>
<dom-module id="my-child">
<template>
<section>
<content></content>
</section>
</template>
<script>
Polymer({
is: 'my-child',
});
</script>
</dom-module>
And the proposed usage of them is the following:
<my-parent>
<my-child>First tab</my-child>
<my-child>Second tab</my-child>
<my-child>Third tab</my-child>
</my-parent>
Online demo: http://jsbin.com/hibuzafapu/1/edit?html,output
The resulting computed HTML code looks something like this:
<my-parent>
<tabs>
<my-child>
<section>
First tab
</section>
</my-child>
<my-child>
<section>
Second tab
</section>
</my-child>
<my-child>
<section>
Third tab
</section>
</my-child>
</tabs>
</my-parent>
If I understood you correctly, then only the <my-child> tag wrapping the <section> tag is redundant. Currently the aforementioned tag does nothing and is just a block-level element that wraps everything (just like a div). If this bothers you, then you can actually omit the <section> tag and put all the styling directly on the <my-child> tag.
In this case, the resulting computed HTML would look something like this:
<my-parent>
<tabs>
<my-child>
First tab
</my-child>
<my-child>
Second tab
</my-child>
<my-child>
Third tab
</my-child>
</tabs>
</my-parent>
UPDATE
In order to add some dynamics to the solution (adding/removing tabs), you have two options: use dom-repeat and stamp the items in light DOM, or push the items array into the my-parent element and use dom-repeat there. Both options are very similar to implement and don't have much difference in the way they work.
Option A: stamping in light DOM:
Definitions for both custom elements remain unchanged, the only difference is how you use them. Instead of hardcoding the light DOM, you make it more dynamic.
<dom-module is="tmp-element">
<template>
<my-parent>
<template is="dom-repeat" items="[[myItems]]">
<my-child>[[item.content]]</my-child>
</template>
</my-parent>
</template>
<script>
Polymer({
is: 'tmp-element',
ready: function() {
this.myItems = [
{ content: "First tab" },
{ content: "Second tab" },
{ content: "Third tab" },
],
};
});
</script>
</dom-module>
<tmp-element></tmp-element>
The tmp-element is used purely to create a binding scope and to feed the data into the dom-repeat.
Live demo: http://jsbin.com/gafisuwege/1/edit?html,console,outputenter link description here
Option B: stamping inside parent:
In this option, the parent needs to have an additional property, in which will we will supply the array of items.
The new version of the my-parent element is the following:
<dom-module id="my-parent">
<template>
<tabs>
<template is="dom-repeat" items="[[items]]">
<my-child>[[item.content]]</my-child>
</template>
</tabs>
</template>
<script>
Polymer({
is: 'my-parent',
properties: {
items: Array,
},
});
</script>
</dom-module>
And the usage is:
<dom-module is="tmp-element">
<template>
<my-parent items="[[myItems]]"></my-parent>
</template>
<script>
Polymer({
is: 'tmp-element',
ready: function() {
this.myItems = [
{ content: "First tab" },
{ content: "Second tab" },
{ content: "Third tab" },
];
},
});
</script>
</dom-module>
<tmp-element></tmp-element>
Here, I have also used a tmp-element (a different one than before) to feed the my-parent its' data.
Live demo: http://jsbin.com/kiwidaqeki/1/edit?html,console,output

How to rerender the complete dom-repeat in Polymer on a Array change

I just started playing with Polymer and have been struggling to solve following issue.
In below code when the button is clicked myItem array is changed and parent template dom-repeat is rerendered, but the child template dom-repeat is not updated.
The reason might be the child dom-repeat is bound to the function _get.
<dom-module id="my-element">
<template>
<button on-click="_removeLastTwo">switch</button>
<template is="dom-repeat" items="{{myItem}}">
<ul>
<template is="dom-repeat" items="{{_get(item)}}">
<li>{{item}}</li>
</template>
</ul>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'my-element',
properties: {
data: {
type: Array,
value: [9,8]
},
myItem:{
type:Array,
value:[1,2,3,4,5]
}
},
_get:function(t){
var d = this.myItem.length;
return [d+1,d+2]
},
_removeLastTwo: function(){
this.myItem = [1,2]
}
});
</script>
How can I overcome this issue, check it at http://jsbin.com/misuvehuwe/edit?html,output . Am I missing any basic approach??

Polymer 1.0 dom-repeat does not trigger filter

Have a simple paper-card with an iron-ajax which is being iterated ok but the filter I have made never triggers. The JSON being fetched via the iron-ajax has an integer value for the day of the week and I only want to have the ones with value of 0.
Tried the filter field with following values:
filter="{{isMonday}}"
filter="{{isMonday(item)}}"
filter="isMonday"
filter="isMonday(item)"
All of these with and without the observe
Component code:
<dom-module id="se-ligor">
<template>
<template is="dom-bind">
<iron-ajax auto
url="http://localhost:5000/leagues/1"
handle-as="json"
last-response="{{ajaxResponse}}">
</iron-ajax>
<template name="my-paper" is="dom-repeat" items="[[ajaxResponse]]" filter="{{isMonday}}" observe="dayofweek">
<paper-card heading="[[item.name]]">
<div class="card-content">
[[item.description]]
[[item.dayofweek]]
</div>
<div class="card-actions">
<paper-button>Some action</paper-button>
</div>
</paper-card>
</template>
</template>
</template>
<script>
Polymer({
is: "se-ligor",
isMonday: function (item) {
console.log(item.dayofweek);
if (item.dayofweek == 0)
return True;
}
});
</script>
</dom-module>
The dom-bind template is intended for binding only in index.html, not in dom-module, so that template should be removed.
The filter property takes the name of a method without delimiters (i.e., no brackets) on your Polymer constructor object.
<!-- in <dom-module> -->
<template is="dom-repeat" items="[[x]]" filter="isMonday" observe="dayofweek">...</template>
<script>
Polymer({
isMonday: function(item) {...}
});
</script>
isMonday contains a typo in return True. In JavaScript, the keyword is lowercase: true.
plunker demo

Polymer 1.0 dom-repeat fails "Uncaught TypeError: Cannot read property 'extends' of undefined"

I have a simple dom-module with an dom-repeat template in it:
<dom-module id="bookmark-extends">
<style>(...)</style>
<template>
<template is="dom-repeat" items="[[extends]]" as="extend">
<a href="[[extend.url]]">
<paper-button>[[extend.__firebaseKey__]]</paper-button>
</a>
</template>
</template>
</dom-module>
<script>
Polymer({
is: 'bookmark-extends',
properties: {
extends: {
type: Array,
notify: true,
value: function(){ return []; }
}
}
});
</script>
Here where I use it:
<dom-module id="bookmark-cards">
<style>(...)</style>
<template>
<firebase-collection
location="*******"
data="{{bookmarks}}"></firebase-collection>
<template is="dom-repeat" items="[[bookmarks]]" as="bookmark">
(...)
<div hidden="[[!bookmark.extendable]]" class="card-actions">
<bookmark-extends extends="[[bookmark.extends]]">
</bookmark-extends>
</div>
<div hidden="[[!bookmark.searchable]]" class="card-actions">
<input-search-on-site id="input" website-name="[[bookmark.__firebaseKey__]]" website-search-url="[[bookmark.searchUrl]]">
</input-search-on-site>
</div>
</paper-card>
</template>
</template>
</dom-module>
<script>Polymer({
is: 'bookmark-cards'
});</script>
I'm getting this error:
Uncaught TypeError: Cannot read property 'extends' of undefined
Please help me, I don't know what to do,
because in my second code the nearly same process is working...
EDIT:
Now I don't use an extra module and don't use the word "extend" anymore...
<div hidden="[[!bookmark.expandable]" class="card-actions">
<template is="dom-repeat" items="[[bookmark.links]]" as="link">
<paper-button>{{link.__firebaseKey__}}</paper-button>
</template>
</div>
The new Error is: "[dom-repeat::dom-repeat]: expected array for items, found Object"
If I try this:
properties: {
links: {
type: Array,
notify: true,
value: function(){ return []; }
}
}
The same error comes.
Couple of things. Move your script element inside the dom-module tag, as per Polymer recommendations.
https://www.polymer-project.org/1.0/docs/devguide/properties.html
Secondly don't use "extends" as an instance variable/property name. Extends is a Polymer keyword for extending existing HTML elements.
https://www.polymer-project.org/1.0/docs/devguide/registering-elements.html
This Plunker shows the key changes: http://plnkr.co/edit/BKzrfC
<dom-module id="bookmark-extends">
<template>
<template is="dom-repeat" items="[[extnds]]" as="extend">
<div>extend</div>
</template>
</template>
<script>
Polymer({
is: 'bookmark-extends',
properties: {
extnds: {
type: Array,
notify: true,
value: function(){ return ['one', 'two']; }
}
}
});
</script>
</dom-module>

Polymer paper menu button

I am very new to web development and am attempting to learn to use polymer to create a simple webpage. I have created a drop down menu populated by the names in a json file similar to the below example. I cannot understand how to display the data associated with the selected menu item. below is the demo code from the polymer project. I understand this question may seem very simple to some of you. Thank you in advance for your patience and any assistance that may be provided.
<paper-menu-button>
<paper-icon-button icon="menu" noink></paper-icon-button>
<paper-dropdown class="dropdown">
<core-menu class="menu">
<template repeat="{{name in food}}">
<paper-item>{{}}</paper-item>
</template>
</core-menu>
</paper-dropdown>
</paper-menu-button>
there are several ways you can check a menu for user input.
method 1
you can use a EventListener to look for the core-select event. to do that you would give the core-menu a id. i am calling it select.
that would make the function look like
this.$.select.addEventListener('core-select', function () {
// access the value with this.selected
});
method 2
you could also use the declarative approach also using a EventListener but this time as a attribute on-core-select="{{selectAction}}" then the function would look like.
selectAction: function () {
// value would be this.$.select.selected if using the select id on the core-menu
}
method 3
you could also use a attribute changed function to get the value when changed. that method would look like.
<paper-menu-button>
<paper-icon-button icon="menu" noink></paper-icon-button>
<paper-dropdown class="dropdown">
<core-menu class="menu" selected="{{selected}}">
<template repeat="{{name in food}}">
<paper-item>{{}}</paper-item>
</template>
</core-menu>
</paper-dropdown>
</paper-menu-button>
the change would call a function that would look something like
selectedChanged: function () {
// value would be this.selected
}
i also made a plunker showing all 3 in use check console for output when selecting http://plnkr.co/edit/odQwNRLFTzyATodQUNh0?p=preview
edit: all this is assuming you are working inside a custom element. outside a custom element method 1 would still work. method 2 and 3 would require a auto-binding template
I'm very new to Polymer too, but I got tabs working this way (i think it may apply to drop-down too):
In normal web-pages:
<body>
<template is="dom-bind" id="app">
<div class="container">
<div class="menu-area">
<paper-tabs selected="{{selected}}" on-iron-select="_onTabSelected">
<template is="dom-repeat" items="[[items]]">
<paper-tab>[[item.name]]</paper-tab>
</template>
</paper-tabs>
</div>
</div>
</template>
<script>
app._onTabSelected = function (e) {
var selectedIndex = e.srcElement.selected;
var item = this.items[selectedIndex];
document.location = item.uri;
};
app.items = [
{id: 'HOME', name: 'Home', uri: "home.html"},
{id: 'PRODUCTS', name: 'Products', uri: "products.html"},
{id: 'USERS', name: 'Users', uri: "users.html"}
];
</script>
</body>
</html>
When composing new elements:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-tabs/paper-tabs.html">
<link rel="import" href="../../bower_components/paper-tabs/paper-tab.html">
<dom-module id="app-header-menu">
<template>
<div class="container">
<div class="menu-area">
<paper-tabs selected="{{selected}}" on-iron-select="_onTabSelected">
<template is="dom-repeat" items="[[items]]"><paper-tab>[[item.name]]</paper-tab></template>
</paper-tabs>
</div>
</div>
</template>
<script>
Polymer({
is: "app-header-menu",
properties: {
items: {
type: Array,
notify: false,
readOnly: false,
value: [
{id: 'HOME', name: 'Home', uri: "home.html"},
{id: 'PRODUCTS', name: 'Products', uri: "products.html"},
{id: 'USERS', name: 'Users', uri: "users.html"}
]
}
},
_onTabSelected: function (e) {
var selectedIndex = e.srcElement.selected;
var item = this.items[selectedIndex];
document.location = item.uri;
}
});
</script>
</dom-module>