I have made a web component "menu" and it has tooltips on hover. But the tooltips are not visible outside the component. As you can see below I've made tooltip with string "abcdefghijklmnopqrstuvxyz". The tooltip is visible "inside" the component and not "on top" of it.
I want it to be visible on top of everything, not only my component.
If the code is any help, here's component:
<link rel="import" href="/bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/iron-icons/iron-icons.html">
<link rel="import" href="/bower_components/paper-menu/paper-menu.html">
<link rel="import" href="/bower_components/paper-toolbar/paper-toolbar.html">
<link rel="import" href="/bower_components/paper-tooltip/paper-tooltip.html">
<link rel="import" href="/bower_components/paper-menu-button/paper-menu-button.html">
<dom-module id="user-menu">
<template>
<paper-toolbar>
<div class="user-photo" style="background-image:url('image.png');"></div>
<div id="user-name-div">placeholder1</div>
<div class="caption-inv">placeholder2</div>
</paper-toolbar>
<paper-menu>
<paper-icon-item>
<iron-icon id="right-menu-logout" icon="icons:exit-to-app" item-icon></iron-icon>
<paper-tooltip for="right-menu-logout" position="top">abcdefghijklmnopqrstuvxyz</paper-tooltip>
<span>Wyloguj</span>
</paper-icon-item>
</paper-menu>
</template>
<script>
Polymer({
is: "user-menu",
});
</script>
</dom-module>
The tooltip anchors to the parent element; to remedy this I would move the paper-tooltip such that the user-menu element is its parent.
or simply add the attribute:
fit-to-visible-bounds="true"
Making it:
<paper-tooltip for="right-menu-logout" position="top" fit-to-visible-bounds="true">abcdefghijklmnopqrstuvxyz</paper-tooltip>
Related
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>
I'm working with Polymer 2.0. Simply trying to create a basic format for my app. I'm using paper-tabs at the bottom of the app and using iron-pages, app-route, and app-location to properly route the tabs to 3 different pages.
The problem I am having is that the element gets loaded in when I click one of the tabs, but then stays on the page when I click on another tab, so I have 2 elements loaded in at the same time.
My code(basically the PSK, but with paper-tabs instead of iron-selector):
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/paper-tabs/paper-tabs.html">
<link rel="import" href="../../bower_components/app-layout/app-layout.html">
<link rel="import" href="../../bower_components/app-layout/app-header-layout/app-header-layout.html">
<link rel="import" href="../../bower_components/app-layout/app-header/app-header.html">
<link rel="import" href="../../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../../bower_components/paper-progress/paper-progress.html">
<link rel="import" href="../../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/app-route/app-location.html">
<link rel="import" href="../../bower_components/app-route/app-route.html">
<link rel="lazy-import" href="/src/blah-app/app-home.html">
<link rel="lazy-import" href="/src/blah-app/app-featured.html">
<link rel="lazy-import" href="/src/blah-app/app-jars.html">
<link rel="lazy-import" href="/src/blah-app/app-fallback.html">
<dom-module id="app-hub">
<template>
<app-location route="{{route}}"></app-location>
<app-route
route="{{route}}"
pattern="/:page"
data="{{routeData}}"></app-route>
<app-toolbar>
<paper-icon-button icon="menu"></paper-icon-button>
<div main-title>blah</div>
<paper-icon-button icon="account-box"></paper-icon-button>
<paper-progress value="10" indeterminate bottom-item></paper-progress>
</app-toolbar>
<paper-tabs
selected="[[page]]"
attr-for-selected="name">
<paper-tab link>
<a class="link" name="home" href="home">Home</a>
</paper-tab>
<paper-tab link>
<a class="link" name="featured" href="featured">Featured</a>
</paper-tab>
<paper-tab link>
<a class="link" name="jars" href="jars">My Jars</a>
</paper-tab>
</paper-tabs>
<iron-pages
selected="[[page]]"
attr-for-selected="name"
fallback-selection="fallback"
role="main">
<app-home name="home"></app-home>
<app-featured name="featured"></app-featured>
<app-jars name="jars"></app-jars>
<app-fallback name="fallback"></app-fallback>
</iron-pages>
</template>
<script>
class AppHub extends Polymer.Element {
static get is() { return 'app-hub'; }
static get properties() {
return {
page: {
type: String,
reflectToAttribute: true,
observer: '_pageChanged',
},
routeData: Object,
subroute: String,
};
}
static get observers() {
return [
'_routePageChanged(routeData.page)',
];
}
_routePageChanged(page) {
// Polymer 2.0 will call with `undefined` on initialization.
// Ignore until we are properly called with a string.
if (page === undefined) {
return;
}
// If no page was found in the route data, page will be an empty string.
// Deault to 'view1' in that case.
this.page = page || 'home';
console.log(page, 'routepagechanged');
}
_pageChanged(page) {
console.log(page, 'pagechanged');
// Load page import on demand. Show 404 page if fails
var resolvedPageUrl = this.resolveUrl('app-' + page + '.html');
Polymer.importHref(
resolvedPageUrl,
null,
this._showPage404.bind(this),
true);
}
_showPage404() {
this.page = 'fallback';
}
}
window.customElements.define(AppHub.is, AppHub);
</script>
</dom-module>
Anyone know why this is happening? If I need to show you the elements being loading in I can, but they are basically just displaying text. Super simple. Thanks!
I think you miss name attribute cause <paper-tabs> must select paper-tab by its name and not <a>. You need to add name attribute to each paper-tab like this:
<paper-tabs
selected="[[page]]"
attr-for-selected="name">
<paper-tab link name="home">
<a class="link" href="home">Home</a>
</paper-tab>
<paper-tab link name="featured">
<a class="link" href="featured">Featured</a>
</paper-tab>
<paper-tab link name="jars">
<a class="link" href="jars">My Jars</a>
</paper-tab>
</paper-tabs>
After much effort, I figured out that I wasn't importing the iron-pages element..
<link rel="import" href="../../bower_components/iron-pages/iron-pages.html">
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
foo.html:
<link rel="import" href="bar.html">
<dom-module id="p-foo">
<template>
<p-bar>
<content select=".myContent"></content>
</p-bar>
</template>
<script>
Polymer( {
is: 'p-foo',
} )
</script>
</dom-module>
bar.html:
<dom-module id="p-bar">
<template>
bar open
<content select=".myContent"></content>
bar closed
</template>
<script>
Polymer( {
is: 'p-bar',
} )
</script>
</dom-module>
demo.html:
<!DOCTYPE html>
<html>
<head>
...
<link rel="import" href="foo.html">
</head>
<body>
<p-foo><div class="myContent"><strong>hello</strong></div></p-foo>
</body>
</html>
The expected output:
bar open
hello
bar closed
What I sometimes get:
bar open
bar closed
hello
The error I am getting is not 100% reproducible. It only happens a percentage of the time I refresh the page. It also appears that the more complicated the content is the higher chance of the error occurring.
It seems that polymer tries to select .myContent before the bar component is has completely rendered.
You need to register your new custom elements with a call to Polymer().
Also, as already stated in comments, your custom elements need to contain an hypen. For example: <p-foo>and <p-bar>.
foo.html:
<link rel="import" href="bar.html">
<dom-module id="p-foo">
<template>
<p-bar>
<content select=".myContent"></content>
</p-bar>
</template>
<script>
Polymer( {
is: 'p-foo',
} )
</script>
</dom-module>
bar.html:
<dom-module id="p-bar">
<template>
bar open
<content select=".myContent"></content>
bar closed
</template>
<script>
Polymer( {
is: 'p-bar',
} )
</script>
</dom-module>
demo.html:
<head>
...
<link rel="import" href="foo.html">
</head>
<body>
<p-foo><div class="myContent"><strong>hello</strong></div></p-foo>
</body>
</html>
I have the following piece of code:
<paper-dropdown-menu id="mydropdown" label="City?">
<paper-listbox class="dropdown-content">
<paper-item>Inbox</paper-item>
<paper-item>Starred</paper-item>
<paper-item>Sent mail</paper-item>
<paper-item>Drafts</paper-item>
</paper-listbox>
</paper-dropdown-menu>
But as seen in the image below, the dropdown-content will have very small width. How can I in a clean way set the width to the same size as the actual paper-dropdown-menu?
I believe I have created what you are looking for in this jsfiddle.
or if you prefer here is the code snippet
.custom {
width: 190px;
}
.custom2 {
width: 400px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<base href="//polygit.org/components/">
<link rel="import" href="polymer/polymer.html">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="paper-item/paper-item.html">
<link rel="import" href="paper-listbox/paper-listbox.html">
</head>
<body unresolved>
<dom-module id='base-page'>
<template>
<paper-dropdown-menu id="mydropdown" class="custom" label="City?">
<paper-listbox class="dropdown-content custom" horizontalAlign='left'>
<paper-item>Inbox</paper-item>
<paper-item>Starred</paper-item>
<paper-item>Sent mail</paper-item>
<paper-item>Drafts</paper-item>
</paper-listbox>
</paper-dropdown-menu>
<br>
<paper-dropdown-menu id="mydropdown" class="custom2" label="City?">
<paper-listbox class="dropdown-content custom2" horizontalAlign='left'>
<paper-item>Inbox</paper-item>
<paper-item>Starred</paper-item>
<paper-item>Sent mail</paper-item>
<paper-item>Drafts</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'base-page',
properties: {}
});
});
</script>
<base-page></base-page>
</body>
</html>
All I did was created a custom class that was applied both to the dropdown-menu and the listbox that gave them each the same width. I believe 190px is the default, but once you have the class you can size it how you want it.
In this u can adjust the width according to you iron-dropdown give the left 0 and width:100%
.custom {
width: 100%;
}
.custom2 {
width: 100%;
}
iron-dropdown{
left:0 !important;
width:100% !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<base href="//polygit.org/components/">
<link rel="import" href="polymer/polymer.html">
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="paper-item/paper-item.html">
<link rel="import" href="paper-listbox/paper-listbox.html">
</head>
<body unresolved>
<dom-module id='base-page'>
<template>
<paper-dropdown-menu id="mydropdown" class="custom" label="City?">
<paper-listbox class="dropdown-content custom" horizontalAlign='left'>
<paper-item>Inbox</paper-item>
<paper-item>Starred</paper-item>
<paper-item>Sent mail</paper-item>
<paper-item>Drafts</paper-item>
</paper-listbox>
</paper-dropdown-menu>
<br>
<paper-dropdown-menu id="mydropdown" class="custom2" label="City?">
<paper-listbox class="dropdown-content custom2" horizontalAlign='left'>
<paper-item>Inbox</paper-item>
<paper-item>Starred</paper-item>
<paper-item>Sent mail</paper-item>
<paper-item>Drafts</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</template>
</dom-module>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'base-page',
properties: {}
});
});
</script>
<base-page></base-page>
</body>
</html>
Actually i believe the two answers by #aditya shrivastava and #jarod moser are not working if you want it the "pure" polymer style.
Here my reasoning:
you use CSS that's not getting shimmed by Polymer
Styles are bleeding through the DOM Tree, which is not intended by Polymer
So my solution here:
set the width of input as proposed in the other two answers
set the with of dropdown with the help of the CSS Mixin:
.custom2 {
--paper-dropdown-menu-button: {
left: 0;
width: 100%;
};
}
The Mixin gets applied to the dropdown box - an iron-dropdown actually - when the CSS is getting rewritten. See the documentation at: https://www.polymer-project.org/1.0/docs/devguide/styling#custom-css-mixins
Then your code should follow this basic setup:
<dom-module id="some-kind-of-element">
<style>
#mydropdown {
--paper-dropdown-menu-button: {
left: 0;
width: 100%;
};
}
</style>
<template>
<paper-dropdown-menu id="mydropdown" label="City?">
<paper-listbox class="dropdown-content">
<paper-item>Inbox</paper-item>
<paper-item>Starred</paper-item>
<paper-item>Sent mail</paper-item>
<paper-item>Drafts</paper-item>
</paper-listbox>
</paper-dropdown-menu>
</template>
</dom-module>
I'm not 100% percent sure about the selector now, but you can see in the web inspector how the styles are added to the elements inside the paper-dropdown-menu element. See the element documentation at polymer: https://elements.polymer-project.org/elements/paper-dropdown-menu to find guidance which CSS Mixins are avaliable to you and play around with them, until you nail it. Maybe you also have to overrule the default settings with the use of !important CSS attribute modifier.
Custom CSS is still quite annoying in Polymer...
to make 'dropdown-content' dependent to width of the paper-dropdown-menu do this:
create your own menu: < resizable-dropdown-menu > copy all component from < paper-dropdown-menu-light > (i like it more), or < paper-dropdown-menu >
import IronResizableBehavior
enter
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
add Polymer.IronResizableBehavior
behaviors: [
//...
Polymer.IronValidatableBehavior,
Polymer.IronResizableBehavior // add this
],
Add this to attached function:
/*
*
* to make menu the same width as container;
*
*/
var ironDropdown = Polymer.dom(this.$.menuButton.root).querySelector('iron-dropdown');
this.addEventListener('iron-resize', (e) => {
ironDropdown.style.width = Polymer.dom(this.root).node.host.offsetWidth+'px';
});