I am using Polymer 1 for web-development and I am encountering a small lack of understanding. Imagine the following:
<div class="value">
<content></content>
</div>
I can easily style the content with the .value selector. Now I only want to style the First content element. :first-child etc. doesn't seem to work.
How can I select different elements of my <content></content> in Polymer?
Thanks!
Note that <content> has been deprecated for <slot>.
To target the first child of the <slot>/<content>, use ::slotted(:first-child):
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
properties: {
foo: {
type: String,
value: 'Hello world!'
}
}
});
});
<head>
<base href="https://cdn.rawgit.com/download/polymer-cdn/1.8.0/lib/">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<x-foo>
<div>first</div>
<div>second</div>
<div>third</div>
</x-foo>
<dom-module id="x-foo">
<template>
<style>
::slotted(:first-child) {
color: red;
}
</style>
<slot></slot>
</template>
</dom-module>
</body>
Related
I am using a custom element that contains a <paper-dialog>, so that I can reuse the dialog style in my application.
The structure is the following:
Polymer({
is: 'dialog-confirm',
properties: {
title: {
type: String,
value: 'Dialog Title',
reflectsToAttribute: true
},
message: {
type: String,
value: 'Dialog message',
reflectsToAttribute: true
}
},
/**
* Triggered when the document is loaded
*/
ready: function () {
var me = this;
},
/**
* Open the dialog
*/
open: function () {
this.$.dialog.open();
}
});
Then, I declare my component as follows in order to have a "prepped" dialog ready to go:
(I removed the <link import="..."> for brevity)
<dom-module id="dialog-confirm">
<template>
<style>
</style>
<paper-dialog id="confirmation"
modal with-backdrop
entry-animation="slide-from-top-animation"
exit-animation="fade-out-animation"
on-iron-overlay-closed="_onSignoutConfirm">
<h2>{{title}}</h2>
<paper-dialog-scrollable>
<p>{{message}}</p>
</paper-dialog-scrollable>
<div class="buttons">
<paper-button class="normal" dialog-dismiss>NO</paper-button>
<paper-button class="positive" dialog-confirm>YES</paper-button>
</div>
</paper-dialog>
</template>
<script type="text/javascript" src="dialog-confirm.js"></script>
</dom-module>
The problem is that this is a component, and I would like to expose the iron-overlay-closed event outside the component. Otherwise, when I re-use my component, I can't data-bind this to a new method, as in:
<dialog-confirm id="myDialog" on-iron-overlay-closed="_myCustomMethod"></dialog-confirm>
Is this possible?
The iron-overlay-closed event already bubbles up from the child component, as seen in the following demo. If it doesn't bubble up for you, the problem might be caused by something else not shown in your question.
<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">
<link rel="import" href="paper-dialog/paper-dialog.html">
<link rel="import" href="paper-button/paper-button.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<x-dialog on-iron-overlay-closed="_myCustomMethod"></x-dialog>
</template>
<script>
HTMLImports.whenReady(() => {
Polymer({
is: 'x-foo',
_myCustomMethod: function() {
console.log('_myCustomMethod: overlay closed');
}
});
});
</script>
</dom-module>
<dom-module id="x-dialog">
<template>
<paper-dialog opened on-iron-overlay-closed="_onIronOverlayClosed">
<div class="buttons">
<paper-button dialog-dismiss>Ok</paper-button>
</div>
</paper-dialog>
</template>
<script>
HTMLImports.whenReady(() => {
Polymer({
is: 'x-dialog',
_onIronOverlayClosed: function() {
console.log('_onIronOverlayClosed: overlay closed');
}
});
});
</script>
</dom-module>
</body>
codepen
I have a simple polymer element that looks like this:
<link rel="import" href="../../bower_components/polymer/polymer.html">
<dom-module id="selector-course">
<template>
<style>
paper-dropdown-menu {
padding:5px;
}
</style>
<paper-dropdown-menu label="Course">
<paper-listbox class="dropdown-content" selected="{{selected}}" attr-for-selected="value" id="courseSelect">
<paper-item value="main">Main</paper-item>
<paper-item value="soup">Soup</paper-item>
<paper-item value="dessert">Dessert</paper-item>
<paper-item value="appetizer">Appetizer</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</template>
<script>
Polymer({
is: 'selector-course'
});
</script>
</dom-module>
This element is stored in a separate HTML file and then used in a couple of my other elements like this:
<link rel="import" href="components/selector-course.html">
...
<selector-course selected="{{recipe.course}}"></selector-course>
Now, within my parent elements I need to access the selected value of <selector-course>
Right now, I have a solution that looks like this:
this.shadowRoot.querySelector('selector-course').shadowRoot.querySelector('#courseSelect').selectedItem.getAttribute("value");
This works, however, this query seems absurdly complex for such a trivial task as accessing the property of an element.
Is there a more simple way to achieve the same thing?
Oh no, this is a very bad idea. Accessing internal elements is very brittle, because it requires parent elements to have deep (pun intended) knowledge about the implementation details of <selector-course>. Not to mention that your method will not work with Shady DOM.
In your case you could simply adding a notifying property to your element
Polymer({
is: 'selector-course',
properties: {
selected: {
notify: true
}
}
});
To select it's value outside data binding you can use the method #a1626 mentions
var selected = this.$('selector-course').selected;
Polymer({
is: 'selector-course',
properties: {
selected: {
notify: true
}
}
});
<!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-dropdown-menu/paper-dropdown-menu.html" rel="import"/>
<link href="paper-listbox/paper-listbox.html" rel="import"/>
<link href="paper-item/paper-item.html" rel="import"/>
</head>
<body>
<template is="dom-bind">
<selector-course selected="{{selection}}"></selector-course>
<div>{{selection}}</div>
</template>
<dom-module id="selector-course">
<template>
<style>
paper-dropdown-menu {
padding:5px;
}
</style>
<paper-dropdown-menu label="Course">
<paper-listbox class="dropdown-content" selected="{{selected}}" attr-for-selected="value" id="courseSelect">
<paper-item value="main">Main</paper-item>
<paper-item value="soup">Soup</paper-item>
<paper-item value="dessert">Dessert</paper-item>
<paper-item value="appetizer">Appetizer</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</template>
</dom-module>
</body>
</html>
Your parent element seems to be a Polymer element in itself as you have used binding. In that case you can access property using
this.$.<id of child>.<property name>
Or in case your element is inside dom-if or dom-repeat
this.$$(<querySelector>).<property name>
You can check it out here
In your case it'll be
<selector-course selected="{{selected}}" id="mySelector"></selector-course>
In javascript
this.$.selected
In Polymer you can use this.$.idOfElement to get an element with an id of idOfElement.
How can I get a dynamically created element by its id if I only have the value of id in a variable?
Note: The element I want to reach out to is created dynamically like this:
<template is="dom-repeat" items="[[days]]" as="o">
<my-custom-element id$="[[getId(o)]]"></my-custom-element>
</template>
I have plenty of these <my-custom-element> in my app and need to get hold of them one by one.
Edit:
None of these work, they all return undefined or null:
this.$[id]
this.$$(id)
this.root.querySelector('my-custom-element#' + id)
Polymer.dom(e.currentTarget).querySelector('my-custom-element#' + id)
You cannot use the automatic node finder (this.$.x) for dynamic nodes. You have to use this.$$(selector), which acts like document.querySelector() constrained to children of the current element.
This why you must use this.$$('#' + nodeId) as suggested by Alan.
Polymer({
is: 'my-elem',
makeRed: function() {
this.$$('#li2').style.color = 'red';
}
});
<!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"/>
</head>
<body>
<my-elem></my-elem>
<dom-module id="my-elem">
<template>
<ul>
<template is="dom-repeat" items='[ 1, 2, 3 ]'>
<li id="li[[item]]">{{item}}</li>
</template>
</ul>
<input type="button" value="make 2 red" on-tap="makeRed" />
</template>
</dom-module>
</body>
</html>
<dom-module id="element-1">
<template>
<input type="text" value={{title}}>
</template>
<script>
Polymer({
properties: {
title: {type: String}
}
})
</script>
</dom-module>
<dom-module id="element-2">
<template>
<element-1></element-1> // Added dynamically using javascript.
</template>
<script>
Polymer({
properties: {
property_1: {type:String}
},
// Here, I can access property_1 by this.property_1
// How to get the property of element-1(title) here?
})
</script>
</dom-module>
So, basically, I have a component (element-2). Inside that component I dynamically add another element (element-1). Now, how the I read the properties of element-1 from element-2?
Any help will be much appreciated.
Polymer has an instance method to query its local DOM:
$$(selector). Returns the first node in this element's local DOM that matches selector.
With this method, you could use this.$$('element-1').title from <element-2>.
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<element-2></element-2>
<dom-module id="element-1">
<template>
<span>{{title}}</span>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'element-1',
properties : {
title: {
type: String,
value: "Hello world!"
}
}
});
});
</script>
</dom-module>
<dom-module id="element-2">
<template>
<div id="container"></div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'element-2',
addElement1: function() {
var e1 = document.createElement('element-1');
this.$.container.appendChild(e1);
},
ready: function() {
this.addElement1();
var e1ref = this.$$('element-1');
console.log("this.$$('element-1').title:", e1ref.title);
}
});
});
</script>
</dom-module>
</body>
codepen
I'm creating a slider web component from scratch to learn.
I want the button to hide when the attribute controlVisible is false and show when it's true, but my selector $('#botaoVoltar') doesn't get anything.
What am I missing?
index.html:
<body>
<slider-js controlVisible='false' ></slider-js>
</body>
polymer.html:
<polymer-element name="slider-js">
<template>
<center>
<div id="container">
<div id="Buttons">
<button name="voltar" id="botaoVoltar"><<</button>
</div>
</div>
</center>
</template>
</polymer-element>
<script>
Polymer('slider-js', {
controlVisible: false,
ready: function () {
if (this.controlVisible === false) {
$('#botaoVoltar').hide();
} else {
$('#botaoVoltar').show();
}
}
});
</script>
The attribute is working fine. If I console.log it, I can see if it is true or false, but the template still renders with the button.
jQuery can't get at Polymer's local DOM, so you'd have to use Polymer's own DOM API. Actually, Polymer's automatic node finding provides quick access to nodes that have IDs with this.$. For instance, you could access the botaoVoltar button in your example with this.$.botaoVoltar.
It looks like you're using old Polymer (pre 1.0). You should switch to the latest version of Polymer (1.5.0). Here's your code upgraded to the newest Polymer version:
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<span>With control-visible:</span>
<x-slider control-visible></x-slider>
<span>Without control-visible:</span>
<x-slider></x-slider>
<!-- Normally, you would define this element in its own file. -->
<dom-module id="x-slider">
<template>
<div id="container">
<div id="Buttons">
<button id="botaoVoltar"><<</button>
<button>>></button>
</div>
</div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-slider',
properties : {
controlVisible: {
type: Boolean,
value: false
}
},
ready: function() {
this.$.botaoVoltar.hidden = !this.controlVisible;
}
});
});
</script>
</dom-module>
</body>
codepen