Considering defining a polymer element
<dom-module id="custom-element">
<template>
<h1>I expect to be green</h1>
</template>
<script>
Polymer({
is: 'custom-element',
properties: {
color: {
type: String,
value: 'red'
}
},
ready: function() {
this.style.color = this.color;
}
});
</script>
</dom-module>
I would expect that the following two would produce the same result:
(in markup)
<body>
<custom-element color="green"></custom-element>
</body>
(in JS)
var customElement = document.createElement('custom-element');
customElement.color = 'green';
document.body.appendChild(customElement);
But in fact it doesn't, as it seems that the properties are set and the polymer 'ready' function is triggered before the customElement is appended to document.body.
So basically I cannot dynamically create (in JS) custom elements and set them initial properties, different than the default properties.
How would you suggest I should do that?
Thanks!
Set the color in attached callback instead of ready. Attached is called after the element has been appended in dom.
<base href="https://polygit.org/components/">
<script src="wecomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<dom-module id="custom-element">
<template>
<h1>I expect to be green</h1>
</template>
<script>
Polymer({
is: 'custom-element',
properties: {
color: {
type: String,
value: 'red'
}
},
attached: function() {
this.style.color = this.color;
}
});
</script>
</dom-module>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
var customElement = document.createElement('custom-element');
customElement.color = 'green';
document.body.appendChild(customElement);
</script>
</body>
</html>
In your case, I would avoid altering the DOM and use a simple attribute binding.
Here is a proof of concept: http://jsbin.com/jozejemumu/1/edit?html,js,output
As you can see, I used attribute binding for the style attribute on the h1 element, which simply sets the CSS color property to whatever the value of the elements' color property is.
The code is faily simple, and looks like this:
<dom-module id="custom-element">
<template>
<h1 style$="color: [[color]];">I expect to be green</h1>
</template>
<script>
Polymer({
is: 'custom-element',
properties: {
color: {
type: String,
value: 'red'
}
}
});
</script>
</dom-module>
Using the element remains unchanged:
<custom-element color="green"></custom-element>
Or:
var customElement = document.createElement('custom-element');
customElement.color = 'orange';
document.body.appendChild(customElement);
Just make sure that the color property contains a valid HTML color name/value.
Related
I need to set the name of a class dynamically executing a function after an iron-ajax request.
In the template section of my element I have:
<div class="{{dynamicClass}}"></div>
I have defined this property like this:
Polymer({
is: "fila-contenido"
,
properties: {
dynamicClass: {
type: Number
}
}
...
I have an on-response function executed when iron-ajax responses:
_onResponse: function (e) {
var nro = e.detail.response.length;
switch(nro){
case 2:
this.dynamicClass = "class2";
break;
case 3:
this.dynamicClass = "class3";
break;
...
}
}
This function set the name of the class correctly.
The problem is the output is not showing the dynamic class but:
<div class="style-scope fila-contenido"></div>
How may I do this?
Thanks!
To bind to the native class attribute, use attribute binding (i.e., class$=). Otherwise, Polymer treats it as a property binding.
<div class$="{{dynamicClass}}">
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo'
});
});
<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>
<x-foo clazz="highlight"></x-foo>
<dom-module id="x-foo">
<template>
<style>
.highlight {
color: blue;
background: lightgray;
}
</style>
<span class$="{{clazz}}">hello world</span>
</template>
</dom-module>
</body>
codepen
Whats the difference between defining a computed property and using it like {{prop}}
prop: {
type: String,
computed: 'some(prop1)'
}
vs a function binding like
{{some(prop1)}}
The property is, as the name implies, also a property of the node object. It can notify outside listeners or reflect to attribute.
Function binding is only used to that. You can call it from the outside but it should have no effect - assuming that the function has no side-effects which is shouldn't.
The most important difference however, is that compute function will evaluate for each binding usage. Computed property will evaluate only once when a dependency changes. See below what happens in the console whenever you click INCREMENT.
Polymer({
is: 'my-elem',
properties: {
i: {
type: Number,
value: 0
},
c: {
computed: 'compute(i)'
}
},
inc: function() {
console.clear();
this.i += 1;
},
compute: function(i) {
console.log('computing property binding');
return i * 2;
},
f: function(i) {
console.log('computing function binding');
return i * 2;
}
});
<!DOCTYPE html>
<html>
<head>
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link href="polymer/polymer.html" rel="import"/>
<link href="paper-button/paper-button.html" rel="import" />
</head>
<body>
<my-elem></my-elem>
<dom-module id="my-elem">
<template>
<div>Computed: [[c]]</div>
<div>Computed: [[c]]</div>
<div>Computed: [[c]]</div>
<div>Computed: [[c]]</div>
<div>Function: [[f(i)]]</div>
<div>Function: [[f(i)]]</div>
<div>Function: [[f(i)]]</div>
<div>Function: [[f(i)]]</div>
<paper-button on-tap="inc">Increment</paper-button>
</template>
</dom-module>
</body>
</html>
I have a behavior that is shared across elements.
In a element i have a on-change="_toggle" switch.
In a second element i have the same code from the first element without the switch button. when the switch is active it reflect to the element containing the switch.
Q: how can i reflect the on-change="_toggle" function across all elements?
my code:
1.
<script>
LanguageBehavior = {
behaviors: [
Polymer.AppLocalizeBehavior
],
properties: {
language: {
value: 'sl',
reflectToAttribute: true
},
},
attached: function() {
this.loadResources(this.resolveUrl('/data/locales.json'));
},
_toggle: function() {
this.language = this.$.switch.checked ? 'en' : 'sl';
// This function is the problem?
}
};
</script>
2
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-toggle-button/paper-toggle-button.html">
<link rel="import" href="../../bower_components/app-localize-behavior/app-localize-behavior.html">
<link rel="import" href="behavior.html">
<dom-module id="bazdara-element-1">
<template>
<style>
:host {
display: block;
}
</style>
{{localize('menu_2')}} // THIS CHANGES WITH THE SWITCH
<span title="english">🇬🇧 SI</span>
<paper-toggle-button on-change="_toggle" id="switch"></paper-toggle-button>
<span title="french">EN</span>
</template>
<script>
Polymer({
is: 'bazdara-element-1',
behaviors: [Polymer.AppLocalizeBehavior, LanguageBehavior],
});
</script>
</dom-module>
3
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/app-localize-behavior/app-localize-behavior.html">
<link rel="import" href="behavior.html">
<dom-module id="bazdara-element-2">
<template>
<style>
:host {
display: block;
}
</style>
{{localize('menu_2')}} // THIS Doesnt change
</template>
<script>
Polymer({
is: 'bazdara-element-2',
behaviors: [Polymer.AppLocalizeBehavior, LanguageBehavior],
});
</script>
</dom-module>
As each element will have its own copy of the behavior your approach is not going to work. Right now the only options i can come up with is:
keep both your elements in one common element and change the property there.
If you are planning to have all your elements in one single html file you can then change this feature in that html file and bind the property to all your elements.
I have a polymer element and inside its Javascript I am trying to find its width and height as it is inside the DOM. I tried many ways but I always get 0 back.
...and here's the one which works for me:
Add the Polymer.IronResizableBehavior behaviour to your element (see https://elements.polymer-project.org/elements/iron-resizable-behavior). Then your element will be sent a iron-resize event when it gets sized. In the handler, check to see whether it's not 0; if not, you're golden.
Untested code follows:
<dom-module id="hard-chicken">
<template>
Hello <span>{{name}}</span>
</template>
</dom-module>
<script>
Polymer({
is: 'hard-chicken',
behaviors: [ Polymer.IronResizableBehavior ],
listeners: { "iron-resize": "onWidthChange" },
onWidthChange: function() {
var w = this.offsetWidth;
if (w > 0)
console.log("width is now ", w);
}
});
</script>
This took way, way too long to figure out...
polymer 1.0
<link rel="import" href="../polymer/polymer.html">
<!--
Here's where you'll define your element. You can define multiple elements
if you want, but the package name will be taken from the first custom
element you define in the file. You can also document your element! For
more info, see [the docs](https://ele.io/docs).
#element hard-chicken
-->
<dom-module id="hard-chicken" attributes="name">
<template>
<style>
:host {
font-family: sans-serif;
}
</style>
Hello {{name}}
</template>
<script>
Polymer({is:'hard-chicken',
/**
* The name of the person you want to say hello to.
* #attribute name
* #type string
* #default "Polymer Dev"
*/
name: 'Polymer Dev',
ready: function() {
console.log(this.offsetWidth);
});
</script>
</dom-module>
You probably want to calculate the width in the attached handler of the element, as that comes last when the unit is actually attached to the DOM.
See https://www.polymer-project.org/1.0/docs/devguide/registering-elements.html#initialization-order
attached: function() {
console.log(this.offsetWidth);
}
This should do it:
attached: function() {
this.async(function() {
console.log(this.offsetWidth);
});
}
Read the documentation at:
https://www.polymer-project.org/1.0/docs/devguide/registering-elements#initialization-order
<dom-module id="hard-chicken">
<style>
:host {
font-family: sans-serif;
}
</style>
<template>
Hello <span>{{name}}</span>
</template>
</dom-module>
<script>
Polymer({
is: 'hard-chicken',
/**
* The name of the person you want to say hello to.
* #attribute name
* #type string
* #default "Polymer Dev"
*/
properties: {
name: {
value : 'Polymer Dev',
type: String
}
},
_getWidth: function () {
console.log(this.offsetWidth);
},
ready: function() {
this.async(this._getWidth, 500);
}
});
</script>
<link rel="import" href="../polymer/polymer.html">
<!-- You can import core and paper elements -->
<link rel="import" href="../core-ajax/core-ajax.html">
<!--
Here's where you'll define your element. You can define multiple elements
if you want, but the package name will be taken from the first custom
element you define in the file. You can also document your element! For
more info, see [the docs](https://ele.io/docs).
#element hard-chicken
-->
<polymer-element name="hard-chicken" attributes="name">
<template>
<style>
:host {
font-family: sans-serif;
}
</style>
Hello {{name}}
</template>
<script>
Polymer('hard-chicken', {
/**
* The name of the person you want to say hello to.
* #attribute name
* #type string
* #default "Polymer Dev"
*/
name: 'Polymer Dev',
ready: function() {
console.log(this.offsetWidth);
}
});
</script>
</polymer-element>
We have a custom element that is making an AJAX call to fetch some html generated on the server side and then injected into its light dom via Polymer.dom(this).innerHTML. The response coming from the server has another custom element in it that exposes a CSS property for theming purposes. On the main page, we're setting the value for the property, but it doesn't appear to be working. How do we get Polymer to style dynamically added light DOM elements that are distributed by another element.
index.html
<style is="custom-style">
x-bar {
--mixin-property: {
background: red;
};
}
</style>
...
<body>
<x-baz>
</x-baz>
</body>
x-baz.html
<dom-module id="x-baz">
<template>
<x-foo></x-foo>
</template>
</dom-module>
<script>
Polymer({
is: "x-baz"
});
</script>
x-foo.html
<dom-module id="x-foo">
<template>
<iron-ajax auto url="..." last-response="{{response}}"></iron-ajax>
<content></content>
</template>
</dom-module>
<script>
Polymer({
is: "x-foo",
properties: {
response: {
type: String,
obeserver: 'responseChanged'
}
},
responseChanged: function(newVal)
Polymer.dom(this).innerHTML = newVal;
}
});
</script>
x-bar.html
<dom-module id="x-bar">
<style>
.elementToStyle {
#apply(--mixin-property);
}
</style>
<template>
<div class="elementToStyle">
...
</div>
</template>
</dom-module>
</script>
Polymer({
is: "x-bar"
});
</script>
The iron-ajax call returns <x-bar> ... </x-bar>.
I would expect the div inside the x-bar that comes back from the AJAX response to have a red background, but it doesn't seem to be working. What do we need to adjust to make this work correctly?
Thanks in advance!