Polymer add class when property is true - polymer

I have seen this in angular before and wondered if this is possible in polymer as well. Angular - What is the best way to conditionally apply a class?
I have set up a property named 'animated':
animated: {
type: Boolean,
value: false,
},
When animated is true, a div inside my element should have a css class of .animate.
<div class=""></div>
For now I have done that inside of the ready function.
But since I came across that Stackoverflow question I wondered if this is prossible in polymer.
Thanks!

One way to do that is using a function as follow:
<div class$="{{_getClass(animated)}}"></div>
Where class$ with $ symbol indicates to Polymer's that property is generate using data binding. So, your _getClass function will look like this:
_getClass: function(animated){
return animated ? "animate" : "";
}
When animate property changes, the _getClass function will be invoked and this function will return the string that indicates the class you need.

You can also use toggleClass method of Polymer
<base href="https://polygit.org/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<dom-module id="my-element">
<template>
<style>
.show {
display: block !important;
border: 1px solid black;
}
.hide {
width: 100px;
height: 100px;
display: none;
}
</style>
<div class="hide" id="toggle"></div>
<button on-tap="_toggleDiv">Press to toggle</button>
</template>
</dom-module>
<script>
Polymer({
is: 'my-element',
properties: {
show: {
type: Boolean,
value: false
}
},
_toggleDiv: function() {
this.show = !this.show;
this.toggleClass('show', this.show, this.$.toggle);
}
});
</script>
<my-element></my-element>

Related

Polymer Inconsistent data with multiple component instances

I am using mp-slider (polymer 2.0) but needed the caption to be a link. I added the property sliderLink (as shown below) Everything seemed to be working except that the URL value for all instances is the value for the last instance. For example, if my links are google.com/1 google.com/2 yahoo.com/1 the links on all slides are yahoo.com/1
To address this I added value: function() { return []; } and I tried a few version of the syntax with no change in my results.
The oddity to me is that with three uses of the property, One instance has the correct value and the other two do not.
<link rel="import" href="../polymer/polymer.html">
<dom-module id="mp-caption">
<template>
<style>
#caption {
width: 100%;
background: var(--caption-background);
padding: 5px 20px;
position: absolute;
bottom: 0;
box-sizing: border-box;
transition: all 2s linear;
}
#caption h3, #caption p { color: var(--white-color) }
#caption h3 {
font-size: 20px;
margin: 10px 0;
padding: 0
}
#caption p {
font-size: 14px;
margin: 5px;
padding: 5px 0
}
</style>
<template is="dom-if" if="{{sliderLink}}">
<div id="caption">
<h3><a href={{sliderLink}}>{{sliderHeader}}</a></h3><!-- incorrect value for sliderLink here -->
<p><a href={{sliderLink}}>{{sliderContent}}</a></p><!-- incorrect value for sliderLink here -->
<p>{{sliderLink}}</p> <!-- correct value for sliderLink here -->
</div>
</template>
<template is="dom-if" if="{{!sliderLink}}">
<div id="caption">
<h3>{{sliderHeader}}</h3>
<p>{{sliderContent}}</p>
</div>
</template>
</template>
<script>
class mpCaption extends Polymer.Element {
static get is() {
return 'mp-caption'
}
static get properties() {
return {
sliderHeader: String,
sliderContent: String,
sliderLink: {String, value: function() { return []; }},
}
}
}
customElements.define(mpCaption.is, mpCaption);
</script>
</dom-module>
The only difference between the three uses is that the last one is not linked. Is this a bug, or am I missing something needed to make these properties URLs?
Thank you
Try binding to the href attribute instead of the property:
<a href$={{sliderLink}}>
For more info see the Polymer docs on binding to native HTML elements.
As Kate Jeffreys told you you should use attribute binding:
<a href$="{{sliderLink}}"></a>
I don't know how are you passing the value of each property but your example works without any problem.
I had to remove the position: absolute so I could see each caption without seeing it one on top of the other.
Another thing I have changed was the property sliderLink, you returned an empty array but doesn't make sense in a property of type String.
Here you can see the code: mp-caption code
Here you can check out the demo: mp-caption demo

Polymer 2.0 : listeners not working

<dom-module id="polymer-starterkit-app">
<template>
<style>
:host {
display: block;
}
#box{
width: 200px;
height: 100px;
border: 1px solid #000;
}
</style>
<h2>Hello, [[prop1]]!</h2>
<paper-input label="hello">
</paper-input>
<div id="box" on-click="boxTap"></div>
</template>
<script>
/** #polymerElement */
class PolymerStarterkitApp extends Polymer.Element {
static get is() { return 'polymer-starterkit-app'; }
static get properties() {
return {
prop1: {
type: String,
value: 'polymer-starterkit-app'
},
listeners:{
'click':'regular'
},
regular:function(){
console.log('regular')
}
};
}
boxTap(){
console.log('boxTap')
}
}
window.customElements.define(PolymerStarterkitApp.is, PolymerStarterkitApp);
</script>
</dom-module>
As shown in the code above, I have tried to define a simple listener on-tap on my div with the class box but it doesn't seem to work!
I think I'm using the wrong syntax.
Also, why should we use listeners if we can simply use predefined listeners like on-click and on-tap?
I would really appreciate any type of help!
Edit: I helped updating Polymer's documentation. It's now very clear and detailed. https://www.polymer-project.org/2.0/docs/devguide/events#imperative-listeners Just read that and you're good. TL;DR: The listeners object is no more in Polymer 2.0, but there's a new way to do it.
You could simply set them up in ready(). There is no need to use .bind() in this case because this will be your custom element in the callback because it's the event's current target.
ready () {
super.ready()
this.addEventListener('my-event', this._onMyEvent)
}
_onMyEvent (event) { /* ... */ }
If you need to listen for events on something that is not your custom element itself (e.g. window), then do it the way it is shown in the Polymer documentation:
constructor() {
super();
this._boundListener = this._myLocationListener.bind(this);
}
connectedCallback() {
super.connectedCallback();
window.addEventListener('hashchange', this._boundListener);
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener('hashchange', this._boundListener);
}
Source: https://www.polymer-project.org/2.0/docs/devguide/events#imperative-listeners
You must create the listener manually
connectedCallback() {
super.connectedCallback();
this.addEventListener('click', this.regular.bind(this));
}
disconnectedCallback() {
super.disconnetedCallback();
this.removeEventListener('click', this.regular);
}
regular() {
console.log('hello');
}
However, to add a listener to an element like the div, you need to add Polymer.GestureEventListeners
class PolymerStarterkitApp extends Polymer.GestureEventListeners(Polymer.Element) {
}

How can I bind a polymer behavior to a child element?

I am reading about Behaviors in Polymer.
I copy/pasted the example for the highlight-behavior.html:
<script>
HighlightBehavior = {
properties: {
isHighlighted: {
type: Boolean,
value: false,
notify: true,
observer: '_highlightChanged'
}
},
listeners: {
click: '_toggleHighlight'
},
created: function() {
console.log('Highlighting for ', this, 'enabled!');
},
_toggleHighlight: function() {
this.isHighlighted = !this.isHighlighted;
},
_highlightChanged: function(value) {
this.toggleClass('highlighted', value);
}
};
Then, in my element i have the following (just the important parts):
<link rel="import" href="highlight-behavior.html">
<dom-module id="highlighting-test">
<template>
<style>
:host {
display: block;
background-color: red;
}
:host.highlighted {
background-color: green;
}
.highlighted {
background-color: green;
}
</style>
<h1>Click anywhere here to toggle highlighting!</h1>
</template>
<script>
Polymer({
is: 'highlighting-test',
behaviors: [HighlightBehavior]
});
</script>
</dom-module>
Now the problem is that the toggling of the highlighted class works when clicking inside the host element but it is not highlighting just the h1 element. It is adding the highlighted class to the host element.
This is how it is rendered in the browser:
<highlighting-test class="highlighted">
<h1 class="style-scope highlighting-test">Click anywhere here to toggle highlighting!</h1>
</highlighting-test>
When clicking I indeed see that it toggles the highlighted class on the host element highlighting-test and the background changes.
How can I make sure that the highlighting behavior is applied to just the h1 tag?
Use this.toggleClass(className, bool, this.$.id_of_element)
Change:
_highlightChanged: function(value) {
this.toggleClass('highlighted', value);
}
to:
_highlightChanged: function(value) {
this.$.hId.toggleClass('highlighted', value);
}
And in HTML add an ID to H1:
<h1 id="hId">Click anywhere here to toggle highlighting!</h1>

Polymer Input Field - Possible to make look more like std html input field?

Is it possible to render the Polymer input field to appear more like a standard html text input field vs the (unfortunate design choice of an) underlined text field? I have googled, but surprisingly cannot find anything that discusses how to achieve this, with examples.
Ref:
https://elements.polymer-project.org/elements/paper-input?active=paper-input-container#styling
I don't see a "background-color" setting. The "container" is always referred to as the "underline".
Update:
I can probably achieve the effect by making a paper-input a child of a paper-card; make the background of the card, white; then size the card to the input field. Since the paper-card has a sharp drop-shadow effect, the field should pop in a similar way to a standard html input field, but will conform to the styling and appearance expected of the framework.
The documentation you linked to lists the available custom properties and mixins that would indeed allow fine-grain control of the styling, including background-color and the underline. It doesn't explicitly list background-color or any other CSS because you'd be able to set that within the custom CSS mixin you provide, as described by the Polymer docs, which note:
It may be tedious (or impossible) for an element author to predict every CSS property that may be important for theming, let alone expose every property individually.
To change the background color of the inner input, you would set the --paper-input-container-input CSS property to a custom mixin, containing background-color:
paper-input {
--paper-input-container-input: {
background-color: rgba(0,0,0,0.1);
}
}
HTMLImports.whenReady(() => {
Polymer({ is: 'x-foo' });
});
<head>
<base href="https://polygit.org/polymer+1.6.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="paper-input/paper-input.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<style>
paper-input.gray {
--paper-input-container-input: {
background-color: rgba(0,0,0,0.1);
}
}
</style>
<paper-input class="gray" label="Inner Gray Background"></paper-input>
</template>
</dom-module>
</body>
To hide the underline in the 3 possible states (default, focus, and disabled), you'd set the corresponding --paper-input-container-underline to a mixin, containing display: none:
paper-input {
--paper-input-container-underline: {
display: none
}
--paper-input-container-underline-focus: {
display: none
}
--paper-input-container-underline-disabled: {
display: none
}
}
HTMLImports.whenReady(() => {
Polymer({ is: 'x-foo' });
});
<head>
<base href="https://polygit.org/polymer+1.6.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
<link rel="import" href="paper-input/paper-input.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<style>
paper-input.no-underline {
/* hide underline in all states */
--paper-input-container-underline: {
display: none
}
--paper-input-container-underline-focus: {
display: none
}
--paper-input-container-underline-disabled: {
display: none
}
}
</style>
<paper-input class="no-underline" label="No Underline"></paper-input>
</template>
</dom-module>
</body>
codepen

Polymer - styling childnodes of host

first, i searched for similar questions but haven't found a solution for my problem, which is basically simple, i guess. :)
I built a simple image-slider for clearing up the whole concepts of web components for myself with a real world example.
My custom component is made out of 5 components and a headline.
stage-slider
stage-element
h1
stage-button
stage-teaserdock
stage-teaser
The component slides fine. Now i wanted to add teaser navigation at the bottom. So first i tried adding a single teaser item.
Ok.. what i want to do is access an element inside of the stage-slider:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../stage-element/stage-element.html">
<link rel="import" href="../stage-button/stage-button.html">
<polymer-element name="stage-slider" attributes="items slideInterval">
<template>
<style>
:host {
width: 960px;
height: 485px;
position: absolute;
top: 50%;
left: 50%;
margin: -242px 0px 0px -480px;
overflow: hidden;
display: block;
}
:content .teaser
{
left: 30px;
}
</style>
<div id="wrapper">
<template id="slider" repeat="{{item in items}}">
<stage-element headline="{{item.headline}}"
image="{{item.image}}"
buttonLabel="{{item.buttonLabel}}"
buttonTargetWindow="{{item.buttonTargetWindow}}"
buttonTargetURL="{{item.buttonTargetURL}}">
</stage-element>
</template>
<content class="teaser" select="stage-teaser"></content>
</div>
</template>
<script src="./libs/TweenLite/easing/EasePack.min.js"></script>
<script src="./libs/TweenLite/plugins/CSSPlugin.min.js"></script>
<script src="./libs/TweenLite/TweenLite.min.js"></script>
</polymer-element>
<script>
Polymer('stage-slider',
{
slideInterval: 7000,
items: [],
index: 0,
ready: function ()
{
console.log('-----------------');
console.log('stage slider ready!');
},
attached: function ()
{
console.log('-----------------');
console.log('stage slider attached!');
this.$.wrapper.style.width = (960 * (this.items.length)).toString() + "px";
//
if (this.items.length > 1 && this.slideInterval != 0)
{
var that = this;
setInterval(function ()
{
that.startSliding(that);
}, this.slideInterval
);
}
},
startSliding: function (shadowDom)
{
console.log('More children than 1 -> SLIDE EM!');
TweenLite.to(shadowDom.$.wrapper, 1.5, {
marginLeft: -960,
ease: Expo.easeInOut,
onStart: function ()
{
console.log('tween started'); //, this = ', this);
},
onComplete: function ()
{
// console.log('tween complete');
// console.log(shadowDom.$.wrapper.getElementsByTagName('stage-slide')[0]);
shadowDom.$.wrapper.style.marginLeft = 0;
shadowDom.$.wrapper.appendChild(shadowDom.$.wrapper.getElementsByTagName('stage-element')[0]);
}});
}
});
</script>
This is how my markup looks like:
<stage-slider slideInterval="0"
items='[
{
"headline" : "Test headline",
"image" : "img/slide0.jpg",
"buttonLabel" : "Test buttonlabel",
"buttonTargetURL" : "http://www.google.com"
}
]'>
<stage-teaser class="teaser"
image="img/teaser0.jpg"
headline="Test teasertext"
targetURL="http://google.com">
</stage-teaser>
</stage-slider>
So there is a stage-teaser element nested inside my stage-slider element.
I thought i have to distribute it to the content tag inside my template element. Which is why there is a content tag like this:
<content class="teaser" select="stage-teaser"></content>
It displays the teaser item correctly.
But now i want to define its css from within the slider component. This is where i am totally stuck..
I can access the element itself with :host, thats good.
But how do i access the content element, which renders the teaser?
i tried the following:
:host(stage-teaser),
:host(.teaser),
:host(#teaser),
:content .teaser,
:host(:content .teaser),
as you can see.. i am kinda stuck. :-/
any idea would be cool!
thanks,
Rob
I suspect that the issue you're seeing is just a typo. Instead of :content you want ::content. Here's a jsbin showing a simple example: http://jsbin.com/mijifiru/1/edit and for more info on styling web components with the shadow DOM, check out this article: http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom-201/
If that doesn't solve the issue it would be helpful if you reduced your code down to a Minimal, Complete, and Verifiable example, and for bonus points do so in an online editor like jsbin.
<polymer-element name='my-container' noscript>
<template>
<style>
::content .innerContent {
background-color: red;
}
</style>
Shadow Dom
<content></content>
</template>
</polymer-element>
<my-container>
<div class='innerContent'>Contained matching Light DOM</div>
<div>Contained unmatched Light DOM</div>
</my-container>