I following the 'Quick tour of Polymer' and there is a section that explain us how to repeat element based on an array, but it only show us how to do it with a template repeater, and I don't really know how its work from behind. I tried to do my own repeater but Polymer inject my code as a string, like unescape characters.
code:
<dom-module id="employee-list">
<template>
[[employe()]]
</template>
<script>
class EmployeeList extends Polymer.Element {
static get is () {
return 'employee-list'
}
constructor () {
super()
this.employees = [
{first: 'Bob', last: 'Li'},
{first: 'Ayesha', last: 'Johnson'},
{first: 'Fatma', last: 'Kumari'},
{first: 'Tony', last: 'Morelli'}
]
}
employe(employees = this.employees) {
let template = '<div>Employee List</div>'
template += employees.map((currentEmployee, id) => {
return `<div>Employee ${id}, FullName : ${currentEmployee.first + ' ' + currentEmployee.last}</div>`
})
return template
}
}
customElements.define(EmployeeList.is,EmployeeList)
</script>
</dom-module>
result:
<div>Employee List</div><div>Employee 0, FullName : Bob Li</div>,<div>Employee 1, FullName : Ayesha Johnson</div>,<div>Employee 2, FullName : Fatma Kumari</div>,<div>Employee 3, FullName : Tony Morelli</div>
And I would like to know if its a form of inject unescape characters / html in Polymer#2
You can use a querySelector within your function to make that happen
html
<template>
<div id="employee-list"></div>
</template>
js
this.querySelector("#employee-list").innerHTML = template
As mentioned by Jordan, you should use dom-repeat
<div> Employee list: </div>
<template is="dom-repeat" items="{{employees}}">
<div>First name: <span>{{item.first}}</span></div>
<div>Last name: <span>{{item.last}}</span></div>
</template>
If you are doing it the way you are to get an id there is an alternative using dom-repeat. You could use the attribute index-as to do that.
<template is="dom-repeat" items="{{employees}}" index-as="id">
You can find out more about dom-repeat here: https://www.polymer-project.org/1.0/docs/api/dom-repeat
Related
I created a Polymer element that displays an address. The address contains \n for new lines, so I wanted to replace it with <br/>.
This is the template:
<br/>
{{sanitizeAddress(address)}}
<br/>
This is the code for sanitizeAddress:
sanitizeAddress: function(unsanitizedAddress) {
var sanitizedAddr = unsanitizedAddress.replace("\n","<br/>");
console.log("sanitizedAddr = " + sanitizedAddr);
return sanitizedAddr;
}
This is the actual output:
FirstLine,<br/>SecondLine
This is the expected output:
FirstLine,SecondLine
How can I make the <br/> go away and display a new line?
By default Polymer autoescapes HTML content in your bindings to prevent you from accidentally ending up with DOM changes you didn't want. An easy way to do it is to assign an id to some element then when the data is available you insert it this way:
<dom-module id="my-element">
<template>
<div id="addressContainer"></div>
</template>
<script>
Polymer({
is: 'my-element',
properties: {
address: {
type: String,
observer: '_addressChanged'
}
},
_addressChanged: function(newValue) {
this.$.addressContainer.innerHTML = newValue;
}
});
</script>
</dom-module>
Just be careful to only do this for HTML that you trust.
I am trying to get two way data-binding between a host element and a template in Polymer using templatizer. For example if I am trying to keep two input boxes in-sync:
<html>
<body>
<my-element>
<template >
<input type="text" value="{{test::change}}" />
<div>The value of 'test' is: <span>{{test}}</span></div>
</template>
</my-element>
<dom-module id="my-element">
<template>
<input type="text" value="{{test::change}}" />
value:
<p>{{test}}</p>
<div id="items"></div>
<content id="template"></content>
</template>
</dom-module>
<script>
Polymer({
is: 'my-element',
test: {
type: String,
value: "a"
},
behaviors: [ Polymer.Templatizer ],
_forwardParentProp: function(prop, value) {debugger},
_forwardParentPath: function(path, value) {debugger},
_forwardInstanceProp: function(inst, prop, value) {debugger},
_forwardInstancePath: function(inst, path, value) {debugger},
ready: function() {
this._instanceProps = {
test: true
};
var templates = Polymer.dom(this.$.template).getDistributedNodes();
template = templates[1];
this.templatize(template);
var itemNode = this.stamp({ test: this.test});
Polymer.dom(this.$.items).appendChild(itemNode.root);
}
});
</script>
</body>
</html>
In the above code I hit the debugger in the _forwardInstanceProp but not any of the others. Why is this? Inside _forwardInstanceProp I can access my-element and manually update the test property. Is there a better way to do this? I also could add an observer on my-element to the test property and then propagate any changes in my-element to the template. Is there a better way to do that? I am just trying to understand what all four of these methods do and when/why they should be used.
It beats my why I can never get neither _forwardParentPath nor _forwardParentProp to run. However, I know when the other two run :)
_forwardInstanceProp runs for direct properties of model passed to stamp and _instanceProps is initialized:
this._instanceProps = {
text: true
};
var clone = this.stamp({
text: this.text
});
_forwardInstancePath on the other hand runs when you pass nested objects to stamp:
var clone = this.stamp({
nested: {
text: this.text
}
});
See this bin for an example: http://jsbin.com/kipato/2/edit?html,js,console,output
In the stamped template there are two inputs bound to two variables which trigger instanceProp and instancePath. Unfortunately I've been unable to fix the error thrown when the latter happens.
I have a simple template that renders an array object. However, it fails with the following message:
[dom-repeat::dom-repeat]: expected array for `items`, found [{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]
The array is passed in the attribute of the custom element in the following format:
[{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]
I have read the docs on template repeaters several times and still unable to find what I am doing wrong.
Any help would be much appreciated!
Here is my custom element:
<dom-module id="x-myelement">
<template>
<div>
<h1>{{title}}</h1>
<ul>
<template is="dom-repeat" as="menuitem" items="{{items}}">
<li><span>{{menuitem.code}}</span></li>
</template>
</ul>
</div>
</template>
<script>
(function() {
Polymer({
is: 'x-myelement',
title: String,
items: {
type: Array,
notify: true,
value: function(){ return []; }
}
});
})();
</script>
</dom-module>
And here is now I use it:
<x-myelement title="Hello Polymer"
items='[{"code":1,"name":"Item #1"},{"code":2,"name":"Item #2"},{"code":3,"name":"Item #3"}]'>
</x-myelement>
You need to put your element properties into the properties object (see the Polymer documentation on properties):
Polymer({
is: 'x-myelement',
properties: {
title: String,
items: {
type: Array,
notify: true,
value: function() {return [];}
}
}
});
Otherwise Polymer has no information about your properties. It treated items as a string and didn't parse the attribute value as a JSON array. Eventually dom-repeat was passed a string for its items property as well, resulting in the error that you saw.
<div id="order">
<template repeat="{{items as item}}">
<p data-id="{{item.id}}" data-qty="{{item.qty}}" data-price="{{item.price}}">
<span>- {{item.id}}</span>
<span> x{{item.qty}}</span>
</p>
</template>
<p>- Total {{total}}€</p>
</div>
Tried itemsChanged first to update the total but that did not work because the observer does not look at the property items[id].qty
The documentation does mention a more specific observer but can not use it when items is a array.
{{items | sum }} fails too because it only updates one time at start up.
Last option is
var order = this.$.order
order.onMutation(order, this.sum)
But then polymer crashes without a error message. I just see a blank screen when I put it in ready:function(){...}
I would say it's not doable right now. or maybe with some crazy hack.
let me suggest that solution:
I have created simple polymer and use power of Computed properties
<polymer-element name="x-repeat">
<template>
<template repeat="{{items as item}}">
<div>{{item.q}}</div>
</template>
<div>Total is {{total}}</div>
</template>
<script>
Polymer({
items : [],
created : function () {
this.items = [{q:1}, {q:2}];
},
computed: { // NOTE: computed set
total: 'items | sum'
},
sum : function (items) { // NOTE : defined 'pipeline' function
var total = 0;
items.forEach(function (i) {
total += i.q;
});
return total;
}
});
</script>
</polymer-element>
Hope that helps!
How to make my custom filter work using bind?
Not Working Example:
JSON:
{ "name": "Adrian" }
HTML:
<template bind="{{user}}">
<p>{{name | filterName}}</p>
</template>
But it works normally when i use repeat.
Working Example:
JSON:
[
{ "name": "Adrian 1" },
{ "name": "Adrian 2" }
]
HTML:
<template repeat="{{user in users}}">
<p>{{user.name | filterName}}</p>
</template>
If you had defined filterName as a function under the elements's prototype...
Polymer('my-element', {
filterName: function(value){
return value.toUpperCase()
}
});
When we do
<template>
{{ user.name | filterName }}
<template>
you have access to your element and its properties 'user', 'users' and the filterName callback.
When you do
<template>
<template bind="{{user}}">
{{name | filterName}}
</template>
</template>
Your outer template has access to user and filterName.
But your inner template is now bound to see only the user object. Your scope is limited to user now. This is a special case when you use bind.
More info here... https://github.com/PolymerLabs/polymer-patterns/blob/master/snippets/basics/using-bind-to-create-a-single-template-instance.html
Nevertheless, there are options for you:
1- Less than ideal -> add the callback as a property in your object. Your model now is responsible for dom transformations. Sucks!
2- If you were to reuse the filter you can turn it into a global expression
PolymerExpressions.prototype.filterName = function (value) {
return value.toUpperCase();
};
And now you can use anywhere.