I try to pass an array to my child component (macroNutriments) and iterate it but it's not working, it seems like the array is not passed at all. The other data are displayed though. I'm totaly new to Polymer.
My parent component :
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../macro-aliment/macro-aliment.html">
<dom-module id="macro-aliments">
<template>
<template is="dom-repeat" items="{{aliments}}">
<macro-aliment
nom = '{{item.nom}}'
quantite = '{{item.quantite}}'
image = '{{item.image}}'
macroNutriments = '{{item.macroNutriments}}'
>
</macro-aliment>
</template>
</template>
<script>
Polymer({
is: 'macro-aliments',
ready : function () {
this.aliments = [
{
nom : 'banane',
quantite : '100g',
image : 'images/banane.svg',
macroNutriments : [
{
nom : 'Glucides',
valeur : '13g'
},
{
nom : 'Protéines',
valeur : '25g'
},
{
nom : 'Lipides',
valeur : '10g'
}
]
},
{
nom : 'pomme',
quantite : '1',
image : 'images/pomme.svg',
macroNutriments : [
{
nom : 'Glucides',
valeur : '13g'
},
{
nom : 'Protéines',
valeur : '25g'
},
{
nom : 'Lipides',
valeur : '10g'
}
]
}
]
}
}
);
</script>
</dom-module>
My child component :
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="macro-aliment">
<template>
<figure>
<img src="{{image}}" alt="">
<figcaption>
<header>
<h1>{{nom}}</h1>
<span>{{quantite}}</span>
<span>{{macroNutriments}}</span>
</header>
<ul>
<template is="dom-repeat" items="{{macroNutriments}}">
<li>
<span>{{item.valeur}}</span>
<span>{{item.nom}}</span>
</li>
</template>
</ul>
</figcaption>
</figure>
</template>
<script>
Polymer({
is: 'macro-aliment',
properties : {
nom : String,
quantite : String,
image : String,
macroNutriments : Array,
},
});
</script>
</dom-module>
Any ideas ?
Problem is here:
macroNutriments : Array,
This property name is in camelCase style, so you should access it like this:
<macro-aliment
nom = '{{item.nom}}'
quantite = '{{item.quantite}}'
image = '{{item.image}}'
macro-nutriments = '{{item.macroNutriments}}'
></macro-aliment>
macroNutriments = ... changes to macro-nutriments = ...
Instead of uppercase character, use dash (-) and the same character but in lowercase. This is just a HTML attributes thing.
Im suggesting two solutions.
Solution 1 (recommended)
Use only lower cases and snake_style for properties naming.
macro_nutriments : Array
I am using this in custom elements properties naming, so I do recommend it to use for you. Never had any problems with this.
This is also what W3Schools recommends. Quote from attributes page
The HTML5 standard does not require lowercase attribute names.
The title attribute can be written with uppercase or lowercase like
title or TITLE.
W3C recommends lowercase in HTML, and demands lowercase for stricter
document types like XHTML.
Solution 2 (NOT recommended)
Use dash and lowercase letter when trying to access this property in HTML code. But this is little bit confusing and there's a VERY big chance that you will be forgetting this over and over again.
Good luck.
Try adding the property for ailments to your parent class.
is: 'macro-aliments',
properties: {
ailments: {
type: Array,
notify: true
}
},
ready: function(){ ...
Related
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
I have a Spring HATEOAS restful api to provide datas for my polymer front-end.
Data is received like this:
GET /api/tips/news :
[ {
"id" : 68,
"content" : "example tip",
"score" : 1,
"creationDate" : 1456257119018,
"links" : [ {
"rel" : "self",
"href" : "http://localhost:81/api/tip/68"
}, {
"rel" : "author",
"href" : "http://localhost:81/api/user/59"
}, {
"rel" : "for",
"href" : "http://localhost:81/api/class/65"
}, {
"rel" : "against",
"href" : "http://localhost:81/api/class/66"
}, {
"rel" : "comments",
"href" : "http://localhost:81/api/tip/68/comments"
} ]
} ]
Problem is that I want to get author property from links, so I want to do a second request once the first one is complete. To do this, I have a component that includes an iron-ajax component, to do the first api with my api Key and all the security stuff.
Here is how I do the first api call:
<bnstips-api uri="/tip/news" result="{{data}}" auto></bnstips-api>
<iron-list items="[[data]]" as="item">
<template>
<tip-card tip=[[item]]></tip-card>
</template>
</iron-list>
and here is the tip-card component:
<dom-module id="tip-card">
<style>
</style>
<template>
<paper-card>
<div class="card-content">
[[tip.content]]
Author:<bnstips-api api-path="[[tip.links.1.href]]" result={{author}} auto></bnstips-api> [[author.name]] [[tip.links.1.href]]
</div>
<div class="card-actions">
<paper-button>Upvote !</paper-button>
</div>
</paper-card>
</template>
<script>
Polymer({
is: "tip-card",
properties: {
tip: {
type: Object,
value: {}
}
}
});
</script>
</dom-module>
the api-path property is used to provide full path instead of just uri, here is the logic behind (in bnstips-api):
if(this.uri != "" || this.uri != undefined){
this.url = basePath+this.uri+"?apiKey="+apiKey;
}
if(this.apiPath != ""){
this.url = this.apiPath+"?apiKey="+apiKey;
}
But I get this:
So the link is provided, but the second ajax request gets a wrong uri, because in the console, I can see that I get a request to http://localhost:81/undefined?apiKey..... even if the property is here.
How to avoid that?
EDIT:
I tried to console.log(this.apiPath) inside my handleRequest() method, and it shows the good value, seems like it's an asynchronous problem (second ajax request is sent before the first one actually ends, so the second one has an undefined path since it has to come from the first one. How to wait for the first one to finish before sending the second one?
I have understood from my last question here that string concatenate is not allowed with 0.9 and above (currently I am migrating to version 1.0).
I have to rather wrap every variable inside separate HTML element.
However there are times when I need to use a href or class attribute to be assigned with values dynamically. I cannot make it to work directly like the following:
Link text
since 1.0 won't allow string concatenation!
Please see the snippets below. I am trying to pass an attribute value from my index.html which in turn should replace the value in class attribute inside my custom element. But it is not working and I understand why.
<dom-module id="multi-color-bar-chart">
<template>
<div id="chart">
<p>{{title}}</p>
<div class="{{v1bg}}">
<!-- I want {{v1bg}} to be replaced by value sent from index.html -->
<span>{{value1}}</span>%
</div>
<div class="v2" style="background:#ffcc00;">
<span>{{value2}}</span>%
</div>
<div class="v3" style="background:#369925;">
<span>{{value3}}</span>%
</div>
<div class="clear"></div>
</div>
<div class="clear"></div>
</template>
<script>
(function () {
Polymer({
is: 'multi-color-bar-chart', //registration of element
properties: {
title: { type: String },
value1: { type: String },
value2: { type: String },
value3: { type: String },
v1bg: { type: String }
}
});
})();
</script>
</dom-module>
Here is the snippet in index.html
<multi-color-bar-chart
title="Annual"
value1="45.5"
value2="22.3"
value3="32.2"
v1bg="#ff0000">
...
...
</multi-color-bar-chart>
I am passing a hex code #ff0000 via v1bg attribute which I intend to actually replace the property inside the element.
I don't know yet if there is a work around to it. Might have used document.querySelector() but didn't try that yet. If there is a direct HTML approach that would be wonderful.
Try class$="{{v1bg}}", as this will bind to the class attribute rather than the class property.
https://www.polymer-project.org/1.0/docs/devguide/data-binding.html#attribute-binding
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.
I am building a basic folder system for a website. I have an array of folder names defined in $scope.folderNames. When I pass this array of folder names into my custom element, it converts the array of stings into one string. E.G. ["cat", "mouse", "dog"] becomes '["cat", "mouse", "dog"]' so that when I reference folderNames[0] it returns '[' instead of "cat". Any idea how I can prevent this from happening?
Jade element call:
folder-menu(id="folder-menu", angupoly="{selected:'$root.height'}", label="Folders", icon="folder", values='{{folderNames}}')
angupoly is a library that allows angular to use Node.bind() to listen to changes in custom element attributes.
Custom element:
<link rel="import" href="/polymer/polymer.html">
<link rel="import" href="/core-menu/core-menu.html">
<link rel="import" href="/core-menu/core-submenu.html">
<link rel="import" href="/core-item/core-item.html">
<polymer-element name="folder-menu" attributes="label icon values selected">
<template>
<core-menu>
<core-submenu icon="{{icon}}" label="{{label}}" selected="{{selected}}">
<core-item label="hi"></core-item>
<template repeat={{v in values}}>
<core-item label="{{v}}">
</core-item>
</template>
</core-submenu>
</core-menu>
</template>
<script>
Polymer('folder-menu', {
publish: {
selected : {value:0, reflect : true},
values : {value: [], reflect : true}
},
attributeChanged: function(attrName, oldVal, newVal) {
console.log(attrName, 'old: ' + oldVal, 'new: ', newVal);
console.log(typeof(newVal));
}
});
</script>
</polymer-element>
Console output:
selected old: null new: 0
string
values old: {{folderNames}} new:
string
values old: new: ["Calls","Flagged","Group1","Group2","Group3"]
string
Couple of things to watch out for:
Polymer will [de]serialize array/object published properties if their type is hinted.
properties which are an object or array are never reflected back to the attribute: http://www.polymer-project.org/docs/polymer/polymer.html#attrreflection. The reflect: true for values in your publish block doesn't do anything.
attributeChanged() will always give you a string value (attributes are always strings). What you want is to observe the values property change in a change watcher (e.g. valuesChanged()). That will give you the object as expected (if you've hinted the type):
Here's te setup:
created: function() {
this.values = []; // hint the type, and initialize in the element instance.
},
valuesChanged: function() {
console.log(this.values, typeof(this.values));
}
http://jsbin.com/xizihana/1/edit