How to dynamically change CSS in polymer? - html

I have a polymer element which is a stack of images that need to expand and reveal each of the images upon hovering on the stack. It's supposed to look like this if left untouched:
And upon hovering, the stack would expand vertically.
The code for the element is (do-profile-pic is another element that puts each image down):
<polymer-element name="do-profile-pic-stack" attributes="images">
<template>
<style>...</style>
<div class="stack-container"
on-mouseover='{{onHovered}}'
on-mouseout='{{onUnhovered}}'>
<template repeat="{{picture, i in images}}">
<div class="stack-img-container"
/* the stack is angled so bit of every image is visible */
style="top: {{5 * i}}; z-index: {{10 - i}}">
<do-profile-pic imgurl="{{picture.url}}" showtime="false">
</do-profile-pic>
</div>
</template>
</div>
</template>
<script>
Polymer('do-profile-pic-stack', {
images: [],
...
});
</script>
</polymer-element>
Now i've looked around, and there seem to be two ways to do this. One is to use the polymer selectors. The other is to use user event methods. I'm not using any of these methods to achieve the default angled layout (comment above). To expand the stack vertically, i'll have to play with positioning and layout, but i cannot seem to think of a good way to implement the this.
The polymer selectors appear complicated.
Programmatically, it looks like playing with HTMLElement will be required. I can do that, but angular-js handles this much better. So is there a better way to go about this that i might be mssing? Thanks.

If you want to change appearance on mouse-over I think you can go with a pure CSS solution with two sets of styles one normal and one for mouse-over.
stack-img-container {
// normal style here
}
stack-img-container:hover {
// mouse-over style
// overrides and extends normal style
}
and put it in your style tag (instead of the dots ...).

Use Element.classList to change class dynamically.
<script src="//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.3/platform.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/polymer/0.3.3/polymer.js"></script>
<my-app></my-app>
<polymer-element name='my-app'>
<template>
<style>
.hovered {
background-color:red;
}
</style>
<span on-mouseenter='{{onHover}}'
on-mouseleave='{{onUnhover}}'>
Mouse over me, please.
</span>
</template>
<script>
Polymer('my-app', {
onHover: function(e) {
e.srcElement.classList.add('hovered');
},
onUnhover: function(e) {
e.srcElement.classList.remove('hovered');
}
})
</script>
</polymer-element>
Notes:
Event.srcElement is not standard will and not work for every user.
The standard way to reference an element within an Polymer element is the Polymer.Base $$(slctr):
this.$$('span').classList.add('hovered');
It works in my project, but not in this snippet.
The code above was copied and edited from Peter Burns' code snippet from How can I handle a hover the Polymer way without external libraries?
Curly braces around onHover in the event handler shouldn't be necessary, however, they don't work otherwise in this snippet. Not sure if it's because of the version of Polymer used. I tried to link to the latest but it failed.
Here is a demo of changing class dynamically with plain javascript.

Related

Polymer access elements within vaadin-grid

Working jsbin illustrating the problem: http://jsbin.com/nomewa/3/edit?html,console,output
I am trying to set the innerHTML of notworking span inside of a template that makes up the vaadin-grid. It does not currently seems to be possible to bind to on-change of vaadin-checkbox when said vaadin-checkbox lies within vaadin-grid since I cannot even access the element within the grid.
It does not currently seems to be possible to bind to on-change of vaadin-checkbox when said vaadin-checkbox lies within vaadin-grid since I cannot even access the element within the grid.
You can use declarative event bindings inside the column tempates, so you don’t have to have a reference to the actual stamped element.
Something like this:
<vaadin-grid-column>
<template>
<vaadin-checkbox on-checked-changed="_myListener">Checkbox</vaadin-checkbo>
</template>
</vaadin-grid-colum>
This is a great way to try some codes (jsbin :) Here this code works but I do not know is it going to fit your need. (I cut and copied only changed parts :
At the property declaration, you may set a pre-value to notWorking property. Then you may change it with dynamically in a function.
<iron-ajax url="https://randomuser.me/api?results=10" last-response="{{response}}" auto></iron-ajax>
<span id="working">Working</span>
<vaadin-grid id="grid" items="{{response.results}}" style="height: auto;">
<vaadin-grid-column>
<template class="header">Name</template>
<template>[[item.name.first]] [[item.name.last]] <span>{{notWorking}}</span></template>
</vaadin-grid-column>
</vaadin-grid>
</template>
<script>
class MyTest extends Polymer.Element {
static get is() { return 'test-component'; }
ready() {
super.ready();
this.set('notWorking',"test")
debugger;
}
}
Here the working link

Create Anchor Element in polymer

Is it possible to create an element that will be used as an anchor in polymer. So for example
<template repeat="{{ content in contentitems }}">
<div id="{{ content.id }}">{{content.stuff}}</div>
</template>
Would it be possible to create a hyperlink to the content#id anchor like http://example.com/#someid
Alternatively, we can query that element with querySelector like the below and then scroll it into view if necessary with JavaScript. I'd rather not have to use a JS router however for anchor hyperlinking?
scrollIntoViewFunc(document.querySelector("html /deep/ #someid"))
Here's an actual URL I want to get working: http://megawac.github.io/status-whiskey/#status-408
The Web Component gods (aka Blink engineers) have decided that anchors inside of shadow-roots will not automatically scroll into view like they do in the main document. For this reason, I believe you will have to do something like you showed to handle this in JavaScript.
After brief searching, I couldn't find a reference to this question in the spec, it really needs to be spelled out somewhere.
If you come up with general solution, elementize it and share it back to the community. =P
Let's say you have a simple-element with some child elements with ids as anchors:
<simple-element>
<div id="anchor1"></div>
<div id="anchor2"></div>
</simple-element>
Then you can make a function to scrollIntoView when the hash changes:
window.addEventListener('hashchange', function() {
let targetElement = document.querySelector('simple-element').$[location.hash.substr(1)];
if(targetElement) {
targetElement.scrollIntoView();
}
}, false);

How can I rewrite the native HTML input element with Polymer?

I want to rewrite the <input type="number"> element with Polymer so that i can <input is="number-input"> and style it in a way so that it looks and behaves the same on different browsers.
This is where I'm at now:
<link rel="import" href="../polymer/polymer.html">
<polymer-element name="number-input" extends="input" attributes="value">
<script>
Polymer('number-input', {
valueChanged: function(){
console.log(this.value)
}
});
</script>
</polymer-element>
... and using it by <input is="number-input">, but it doesn't fire the valueChanged function.
What am I doin wrong?
Teltrik did a recent article on styling inputs with shadow dom that was pretty interesting: http://developer.telerik.com/featured/comprehensive-guide-styling-file-inputs/
In your case, you're doing everything correctly. The problem however, is that input already has a .value property. You're trying to override the native property which creates unpredictable behavior. The second issues is that Object.observe() cannot observe native properties on elements. For example, if you added the hidden attribute, hiddenChanged would never be called. Likewise for title and titleChanged.

Is it possible to inject HTML into a polymer component via an attribute?

I'm using one of the core polymer components that basically has:
<polymer-element attributes="label">
<div>{{label}}</div>
as part of the source. I'd like to inject some HTML into this so that it ultimately renders as:
<div>Item <small>Description</small></div>
Is there any way to do this without copying the entire component (which is basically impossible considering the dependency chain)?
Polymer doesn't allow setting HTML inside {{}} expressions because it's a known XSS outlet. However, there are ways around it (1, 2).
I'm not sure there's a great way around this issue but I found something that works. You want to extend the element but also need to modify its shadow dom because of the .innerHTML limitation. Taking paper-button as an example, it has an internal {{label}}. You could extend the element, drill into its shadow dom, and set .innerHTML of the container where {{label}} is set. React to label changing (labelChanged) and call this.super():
<polymer-element name="x-el" extends="paper-button">
<template>
<shadow></shadow>
</template>
<script>
Polymer('x-el', {
labelChanged: function() {
// When label changes, find where it's set in paper-button
// and set the container's .innerHTML.
this.$.content.querySelector('span').innerHTML = this.label;
// call paper-button's labelChanged().
this.super();
}
});
</script>
</polymer-element>
Demo: http://jsbin.com/ripufoqu/1/edit
Problem is that it's brittle and requires you to know the internals of the element you're extending.

Polymer document.querySelector not working as expected

Either I am doing something horribly wrong or Polymer just doesn't like me. See following:
<polymer-element name="menu-paper-ui" noscript>
<template>
<paper-dialog heading="Dialog" transition="paper-dialog-transition-bottom">
[ .. ]
</paper-dialog>
<paper-button label="Dialog Bottom" on-tap="{{toggleDialog}}"></paper-button>
</template>
<script>
Polymer('menu-paper-ui', {
toggleDialog : function() {
var dialog = document.querySelector('paper-dialog');
console.log(dialog); //returns null
dialog.toggle();
}
})
</script>
</polymer-element>
Now, I have my reasons to use querySelector. So, if someone can tell me whats going wrong that will be great!
This question is nearly identical to Using querySelector to find nested elements inside a Polymer template returns null.
The short answer is that elements in a polymer-element's template are put into the ShadowDOM of that element, are not not visible to the anything outside of that element. This is so that you can control styling more easily, and element IDs are scoped.
You can either give the dialog an id and use Polymer's automatic node finding, or use this.shadowRoot.querySelector('paper-dialog').
The Problem is that you can not access the shadow DOM inside a custom element with document.querySelector. See my answer to a similar question.