We saw previously that we could set a custom element's property and have that value changed in the DOM.
In that case, we set a boolean and <span>{{warning}}</span>
changed. That is, the DOM changed.
However, if we want to bind a variable to an attribute, <div warning="{{warning}}">hi</div>
, then the DOM won't automatically change when the property does, although the underlining javascript value will.
So we have to use the <div warning$="{{warning}}">hi</div>
syntax instead to change the DOM attribute. If we combine this with some CSS selectors, we can use it to style the element.
div {
background-color: pink;
}
div[warning] {
background-color: red;
}
Notes:
Full source: an-ele.html
<link rel="import" href="bower_components/polymer/polymer.html">
<dom-module id="an-ele">
<style>
div {
background-color: pink;
}
[warning] {
background-color: red;
}
</style>
<template>
<div warning$="{{warning}}">hi</div>
</template>
<script>
Polymer({
is: "an-ele",
properties: {
warning: {
type: "Boolean"
}
}
});
</script>
</dom-module>
Full source: index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="an-ele.html">
</head>
<body>
<template id="app" is="dom-bind">
<an-ele warning="{{warning}}" on-tap="clicky">
</an-ele>
</template>
</body>
<script>
window.addEventListener('WebComponentsReady', function(e) {
var t = document.querySelector('#app');
t.clicky= function(e) {
var t = Polymer.dom(e).localTarget;
t.warning = !t.warning;
};
}
</script>
</html>
We've learnt how to set custom properties on custom elements.
But we may want to communicate data between the host element and the custom element. We can use a property on the custom element for this.
In the host document, index.html in this case, we'll have a script tag that sets a property on a 'dom-bind' template called 'warning'.
window.addEventListener('WebComponentsReady', function(e) {
var t = document.querySelector('#app');
t.warning = true;
});
Now in our template code in index.html we'll reference the {{warning}}
property and also pass it to our custom element.
<template id="app" is="dom-bind"><div>{{warning}}</div>
<an-ele warning="{{warning}}" on-tap="clicky"></an-ele>
...
</template>
Now in our custom element, set an on-tap
event listener and change the value of 'warning' in that.
...
<template><div on-tap="clicky">hi</div>
</template><script>
Polymer({
is: "an-ele",
properties: {
warning: {
type: "Boolean",
notify: true
}
},
clicky: function() {
this.warning = !this.warning;
}
});
</script>
...
Note the notify
property that's been added to the 'warning' property. This makes sure any changes to 'warning' in the element bubble up to the hosts, our template in index.html for example.
Now when we tap on the div in our custom element, the value in index.html will automatically update.
Note:
Full source: an-ele.html
<link rel="import" href="bower_components/polymer/polymer.html">
<dom-module id="an-ele">
<template>
<div on-tap="clicky">hi</div>
</template>
<script>
Polymer({
is: "an-ele",
properties: {
warning: {
type: "Boolean",
notify: true
}
},
clicky: function() {
this.warning = !this.warning;
}
});
</script>
</dom-module>
Full source: index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="an-ele.html">
</head>
<body>
<template id="app" is="dom-bind">
<div>{{warning}}</div>
<an-ele warning="{{warning}}"> </an-ele>
</template>
</body>
<script>
window.addEventListener('WebComponentsReady', function(e) {
var t = document.querySelector('#app');
t.warning = true;
});
</script>
</html>
The shim used for CSS variables is lightweight.
This means you have to use element.updateStyles()
in places where you'd like it to be automatic.
We've seen we need to use it if we dynamically update a CSS variable using element.customStyle.
Additionally, in a custom-style
in index.html for example, if you have a style that changes a CSS variable based on a class selection:
an-ele {
--an-ele-name-bgcolor: green;
}
an-ele.warning {
--an-ele-name-bgcolor: warning;
}
Then, without updateStyles()
, nothing will happen if add or remove the 'warning' class from 'an-ele'. If you want to want to see the change you need to call element.updateStyles().
However, if instead you define two CSS variables in your custom element, and change the class at runtime, then it will work:
Within your custom element's style tag:
:host {
background-color: var(--an-ele-name-bgcolor, white);
}
:host.warning {
background-color: var(--an-ele-name-bgcolor-warning, white);
}
Within your index.html custom-styles
style tag:
an-ele {
--an-ele-name-bgcolor-warning: red;
--an-ele-name-bgcolor: purple;
}
Then changing the 'warning' class at runtime will work without a call to updateStyles(), since the css variables shim no longer needs to change a CSS variable at runtime.
Event retargeting makes an event from a custom element look like it's coming from the overall custom element tag, as opposed to an element within.
For example:
<dom-module id="an-ele">
<template>
<span on-click="clicky">hi</span>
</template>
...
An event from the span tag would be retargeted to come from the 'an-ele' tag when it bubbles up to a parent listener.
Event retargeting was part of ShadowDOM. But the more performant ShadyDOM -- the default in 1.0 -- does not have this.
But Polymer.dom(e).localTarget
will retarget an event object for you to the overall tag.
Given a custom element in index.html which has a on-tap
listener, this method on the dom-bind template will give you to retargeted event:
t.clicky= function(e) {
var t = Polymer.dom(e);
console.log("retargeted:", t);
console.log("normal:", e);
}
Giving the output:
retargeted: Polymer.EventApi.EventApi {event: (...), rootTarget: (...), localTarget: (...), path: (...)}
normal: CustomEvent {detail: Object, ....
Full source: index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="an-ele.html">
</head>
<body>
<template id="app" is="dom-bind">
<an-ele on-tap="clicky">
</an-ele>
</template>
</body>
<script>
var t = document.querySelector('#app');
t.clicky= function(e) {
console.log("retargeted:", Polymer.dom(e));
console.log("normal:", e);
};
</script>
</html>
Full source: an-ele.html
<link rel="import" href="bower_components/polymer/polymer.html">
<dom-module id="an-ele">
<template>
<span>hi</span>
</template>
<script>
Polymer({
is: "an-ele"
});
</script>
</dom-module>
Previously, we showed how one CSS property in your custom element could be styled from the outside using a shim for CSS variables.
But we often want to allow the user to style not just one rule for a class, not even many, but anything for that class.
Polymer 1.0 uses an experimental feature called mixins that allows the element user to specify any CSS property for a class.
We @apply(--an-ele-name-theme)
in CSS selector for the class in the custom element:
<dom-module id="an-ele"><style>
.name {
@apply(--an-ele-name-theme);
}
</style>
...
Then in the index.html, or hosting custom element, we specify the --an-ele-name-theme
under the selector for our element, and add the styles there.
<style is="custom-style">
an-ele {
--an-ele-name-theme: {
display: block;
color: white;
font-weight: bold;
background-color: blue;
};
}
</style>
Notes:
is="custom-style"
is only needed if your styling the element from index.html not a polymer element.Full source: an-ele.html
<link rel="import" href="bower_components/polymer/polymer.html">
<dom-module id="an-ele">
<style>
.name {
@apply(--an-ele-name-theme);
}
</style>
<template>
<span class="name">hi</span>
</template>
<script>
Polymer({
is: "an-ele"
});
</script>
</dom-module>
Full source: index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
<link rel="import" href="an-ele.html">
<style is="custom-style">
an-ele {
--an-ele-name-theme: {
display: block;
color: white;
font-weight: bold;
background-color: blue;
};
}
</style>
</head>
<body>
<an-ele>
</an-ele>
</body>
</html>