So I have been trying to put together a custom storage element with Polymer which uses the polymer-localforage element inside it. The local forage element requires that you set it's name attribute and so I thought that I could simply pass the "name" attribute or "id" attribute from my custom element over to the local forage element in my template, but it doesn't work. To make sure I wasn't doing something wrong I did a custom element which just inserts the "name" attribute of the root into the "name" attribute of a div inside the template tag but that doesn't work either.
<dom-module id="x-custom">
<template>
<div name="{{name}}">Hello {{name}}</div>
</template>
</dom-module>
and the script
Polymer({
is: 'x-custom',
properties:{
"name": {
type: String
}
}
});
if I use the element
<x-custom name="foo" />
What I then get is
<div class="style-scope x-custom">Hello foo</div>
No name attribute at all, not even a blank one.
How can I drop a template value into an attribute of a child element?
Try adding $ at the end of attributes as below.
<dom-module id="x-custom">
<template>
<div name$="{{name}}">Hello {{name}}</div>
</template>
</dom-module>
The Polymer docs refer to this as annotated attribute binding.
Related
I was contemplating some code which would wrap each child of of the web component. Something like:
<dom-module id=test">
<template>
<template is="dom-repeat" items="{{contents.children}}">
<div>
{{item}}
</div>
</template>
</template>
</dom-module>
so what would happen is if i did something like:
<test>
<span>foo</span>
<span>bar</span>
</test>
it would kick out:
<test>
<div><span>foo</span></div>
<div><span>bar</span></div>
</test>
I was looking over ways i could do this, but i am having issues trying to create the dom-repeat correctly since contents.children isnt a real property.
Edit i was looking at what attributes are allowed for content tags, which is select plus all globals.
So in theory, i could assign an ID and then get the children of it?
<content id="myContent"></content>
and then in the dart say:
ContentElement get _content => $['myContent'];
#property HtmlElement children = [];
a.created(): super.created(){
set("children", _content.children);
}
and then mark the template accordingly?
<template is="dom-repeat" items="{{children}}">
...
</template>
It looks like you would like to wrap certain elements and add some new functionality to them.
The simplest (and most Polymer-ish) way to do that, is to introduce another custom element, which is (only) responsible for the wrapping.
Your test element (which, by the way, has an incorrect name - the name must contain a dash) would then look like this:
<dom-module id=test-element">
<template>
<content></content>
</template>
</dom-module>
(I fixed the naming according to convention. Renamed from test to test-element.)
And the newly created wrapper element (named wrapper-element) should look something like this:
<dom-module id=wrapper-element">
<template>
<div><content></content></div>
</template>
</dom-module>
Everything put together, the usage would be something like this:
<test-element>
<wrapper-element><span>foo</span></wrapper-element>
<wrapper-element><span>bar</span></wrapper-element>
</test-element>
With this, you get a clean solution, where you don't even need any JS code for the wrapping logic.
Question
Which method of placing the <script> tags is "best-practice?"
Inside the <dom-module>?
or
Outside the <dom-module>?
Also, please answer:
Why?
What is the source of your answer?
What downside risks are there by doing it the "wrong" way?
Polymer Starter Kit: OUTSIDE
In the Polymer Starter Kit, the my-list.html and my-greeting.html files place the <script> tag outside the <dom-module>.
Like this:
<dom-module>
<style>...</style>
<template>...</template>
<dom-module>
<script>...</script>
Other Experts: INSIDE
However, I have heard and seen several examples from Google employees and Google developers that suggest the <script> tags should go inside the <dom-module>.
Like this:
<dom-module>
<style>...</style>
<template>...</template>
<script>...</script>
<dom-module>
The correct answer is - it shouldn't matter. While the documentation is indeed as #Mowzer noted, this is just an example rather than a definition. At least some actual Polymer elements like e. g. iron-image have it outside dom-module.
The relationship between the dom-module and the object Polymer constructor defines is established through the 'is' property of the object passed to the Polymer constructor and the id attribute of the dom-module.
From Local DOM guide:
Give the <dom-module> an id attribute that matches its element’s is property and put a inside the <dom-module>. Polymer will automatically clone this template’s contents into the element’s local DOM.
As a side note, you can also successfully use <script src="external.js"></script> to separate the html from the JS - I'm just guessing this is one possible reason for this question. The only drawback to this (AFAIK) is that in this case a vulcanized version of your element will show incorrect (offset) code line numbers for JS errors.
Looks like <script> tags should go inside the <dom-module>.
Per this definition in the developer guide.
Element definition
<dom-module id="element-name">
<template>
<style>
/* CSS rules for your element */
</style>
<!-- local DOM for your element -->
<div>{{greeting}}</div> <!-- data bindings in local DOM -->
</template>
<script>
// element registration
Polymer({
is: "element-name",
// add properties and methods on the element's prototype
properties: {
// declare properties for the element's public API
greeting: {
type: String,
value: "Hello!"
}
}
});
</script>
</dom-module>
I'm building a menu with a dom-repeat template like this:
<template is="dom-repeat" items="{{appletsMenu}}">
<a data-route="{{item.dataRoute}}" href="{{item.href}}">
<iron-icon icon="{{item.icon}}" src="{{item.iconSrc}}" ></iron-icon>
<span>{{item.name}}</span>
</a>
</template>
The data-route attribute is not filled though in the generated DOM:
...
...
It seems that the template only renders "normal" attributes like href. Am I'm missing something? Thanks.
To bind to an attribute, use $= rather than =. This results in a call to:
element.setAttribute(attr, value);
As opposed to:
element.property = value;
(source)
So in your case:
<a data-route$="{{item.dataRoute}}" href="{{item.href}}">
I'm tinkering around with Polymer again and there is something I want to do but it doesn't work and the workaround looks so messy. I want to style an element but take advantage of Data Binding. Basically I try to do this:
<dom-module id="proto-element">
<template>
<style>
#wrapper{
width:{{pixels}};
background: #e1e1e1;
}
#bar{
width:80%;
}
</style>
<div id="wrapper">
<div id="bar" style$={{barStyle}}>I'm the bar! <b>{{test}}</b></div>
</div>
</template>
</dom-module>
<script>
Polymer({
is: "proto-element",
ready: function() {
this.pixels = "300px";
this.test = "Fear me!"
}
});
</script>
The text bound to this.test works flawlessley. But the moustache tags that are inside of style get ignored. Is there a simple solution to this? Because using the inline style$= syntax is super messy when you are working with multiple css rules and also you always need to concatinate a string for it to work if the value you want is obtained elsewhere. Any ideas on a nice clean solution?
I'm afraid what you want is (at least currently) not possible. Data-binding works only inside <template> tags, either a <template is="auto-binding"> or the template inside a <dom-module>.
In the <style> tag, data-binding simply won't work. You could try putting another <style> tag INSIDE the <template> tag (which is messy), but you still won't get the data-bound property to work, since the curly brackets {{...}} must be inside an individual tag and can't be (currently) surrounded by whitespaces (spaces, newlines, ...), see docs:
String concatenation is not supported inside a tag, and the tag can’t contain any whitespace ...
tl;dr: There are two issues that prevent you from achieving what you want: 1) Data-binding only works inside a template tag and 2) if you want to print out data-bound properties, they must be enclosed inside a html tag.
You could try a different approach:
ready: function () {
this.$.wrapper.style.width = '300px';
}
this.$ allows you to easily access any DOM element with an id attribute (for example your #wrapper, which is accessed as this.$.wrapper) and from there, you can set any other attribute of the element (this.$.wrapper.style.width in this case).
EDIT: Also, I just noticed that you've actually put <style> tag inside the <template>, which is not advised. Since Polymer 0.8, this is the recommended structure for a custom element:
<dom-module>
<style> ... </style>
<template> ... </template>
</dom-module>
<script> ... </script>
Check out the Overview and Migration guide.
EDIT 2: As of Polymer 1.1 the suggested element structure (as pointed out by Max Waterman) has been updated to:
<dom-module>
<template>
<style> ... </style>
...
</template>
<script> ... </script>
</dom-module>
Let's say I have something like:
<code>
<polymer-element name'my-element'>
<template>
<div>{{label}}</div>
</template>
</polymer-element>
</code>
Would it be possible for me to simply declare my element this way:
<code>
<my-element label='name'></my-element>
</code>
What I'm doing doesn't seem to work. Is there a straightforward way to bind in the markup?
There are a few issues with what you posted, you are missing an '=' after 'name' in your polymer-element, and you have to either call Polymer to register my-element or include noscript attribute.
In general, if you construct your question in JsBin (or similar) you can make sure you've resolved such issues which otherwise obscure the nature of your question.
Bottom line is that you must make label a published property before Polymer will automatically connect it to attributes. You can make it published by including the name in the attributes attribute of the polymer-element, like this:
<polymer-element name="my-element" attributes="label" noscript>
http://jsbin.com/kizahi/1/edit
<my-element label="name"></my-element>
<polymer-element name="my-element" attributes="label" noscript>
<template>
<div>{{label}}</div>
</template>
</polymer-element>