How to make iron-a11y-keys work on the entire page? - polymer

My keypresses (right and left keys) only throw events when I've clicked in certain parts of my page. How do I make it so my iron-a11y-keys work on the entire page?
Here's what I have now:
<template>
<iron-a11y-keys keys="left right" on-keys-pressed="onRightKey"></iron-a11y-keys>
<paper-drawer-panel id="drawerPanel" responsive-width="1024px" drawer-width="{{drawerWidth}}">
...
</paper-drawer-panel>
</template>
It seems to behave the same way when I set target={{}}. I'm not certain what the target parameter does so that may be my problem. A bit of education on that would also be appreciated.

<template>
<iron-a11y-keys id="a11y" keys="left right" on-keys-pressed="onRightKey"></iron-a11y-keys>
<paper-drawer-panel id="drawerPanel" responsive-width="1024px" drawer-width="{{drawerWidth}}">
...
</paper-drawer-panel>
</template>
and in the script:
ready: function() {
this.$.a11y.target = document.querySelector('body');
}

Related

How to set <iron-scroll-threshold> scroll-target to "document" for Polymer Starter Kit

I intend to implement an infinite scroller using with PSK v3 by setting the scroll-target to "document", but it just doesn't work for PSK. Below is the code snippet:
<iron-scroll-threshold id="threshold"
scroll-target="document"
on-lower-threshold="queryMoreData">
<iron-list items="[[items]]" grid>
<template>
<div>
<div class="content">
item: [[item.n]]
</div>
</div>
</template>
</iron-list>
</iron-scroll-threshold>
I have tested scroll-target="document" with plain HTML, and it's working nicely. I want to know how should it be set for PSK to trigger an event when user scroll to the end of a particular page/view.
Apparently, you need to set the scroll-target of <iron-scroll-threshold> to the scroll-target of <app-header> with the following code in ready():-
ready() {
{ // Set scroll target for <iron-scroll-threshold>
let myApp = document.querySelector('my-app');
let appHeader = myApp.shadowRoot.querySelector('app-header');
this.$.threshold.scrollTarget = appHeader.scrollTarget;
}
}
Sometimes, your scroll position is at enough lower place at start than queryMoreData functions fire ones. In this function, you will need to clear the threshold by calling the clearTriggers method into queryMoreData function :
queryMoreData() {
//check if you have more data to load than
ironScrollTheshold.clearTriggers();
}
After which it will begin listening again for the scroll position to reach the threshold again assuming the content in the scrollable region has grown.
You have to set the scroll-target attribute of the iron-scroll-threshold element to 'document'.
Also note the scroll-target attribute of the iron-list is set to the id of the iron-scroll-threshold element - 'threshold'.
<iron-scroll-threshold scroll-target="document" id="threshold" on-lower-threshold="loadMoreData" lower-threshold="100">
<iron-list id="list" items="[[items]]" as="item" scroll-target="threshold" grid>
<!-- template -->
</iron-list>
</iron-scroll-threshold>

Polymer event on-content-scroll not firing

I have an iron-list which I add new items to while scrolling to the bottom using iron-scroll-threshold. That works fine.
What I also need is a general event which is fired when scrolling stops.
I need that to know whether the listed items (m.message) have been seen by the user, by checking which items are currently visible in the view-port after scrolling, and then marking them as "read".
<div class="container" on-content-scroll="_scrollHandler">
<iron-scroll-threshold id="threshold" scroll-target="mlist" lower-threshold="500" on-lower-threshold="_loadMoreData"></iron-scroll-threshold>
<iron-list items="[[messages]]" id="mlist" as="m">
<template>
<div>
<p>[[m.message]]</p>
</div>
</template>
</iron-list>
</div>
The handler _scrollHandler is never fired however.
What would be necessary to get an event after scrolling ends?
You need the style: overflow: auto on the div.container. This will make sure the scroll event will invoke.
I could not find any such event as content-scroll, but with the changes above you should be able to change your HTML to bind against the handler like: on-scroll="_scrollHandler".
To detect if scrolling has stopped, I'd recommend using Polymer.debounce to have the callback set the isScrolling state to false like:
app._scrollHandler = function (e) {
app.isScrolling = true
app.debounce('scroll-handler', _ => {
app.isScrolling = false
}, 20)
}
It works at the end by moving on-scroll="_scrollHandler" to the iron-list:
<div class="container">
<iron-scroll-threshold id="threshold" scroll-target="mlist" lower-threshold="500" on-lower-threshold="_loadMoreData"></iron-scroll-threshold>
<iron-list items="[[messages]]" id="mlist" as="m" on-scroll="_scrollHandler">
<template>
<div>
<p>[[m.message]]</p>
</div>
</template>
</iron-list>
</div>
With the function being:
_scrollHandler: function() {
this.debounce("markAsRead", function(e) {
console.log("debounce");
}, 500);
}
Edit:
In case the iron-scroll-threshold wraps the iron-list, you need to move on-scroll to the iron-scroll-threshold-element:
<iron-scroll-threshold on-scroll="_scrollHandler" id="threshold" on-lower-threshold="_loadMore">
<iron-list scroll-target="threshold">...</iron-list>
</iron-scroll-threshold>

How to set scroll-target on an iron-list within an app-header-layout with has-scrolling-region

I am trying to use an iron-list (and iron-scroll-threshold) within a app-header-layout with has-scrolling-region.
I generated the basic app layout with the polymer-CLI.
If I do not use has-scrolling-region on the app-header-layout and use "document" for scroll-target on the iron-list it kinda works. But with this solution the scrollbar belongs to the window and does not slide beneath the header and I obviously cannot get the nice "waterfall" behaviour that is usually associated with these kinds of layouts.
Therefore, I use has-scrolling-region on the app-header-layout, but what is the right way to pass the corresponding scoller to the scroll-target property of the iron-list?
<!-- Main content -->
<app-header-layout has-scrolling-region id="layout">
<app-header condenses reveals effects="waterfall">
<app-toolbar>
<paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
<div title>Twiamo</div>
</app-toolbar>
</app-header>
<iron-pages role="main" selected="[[page]]" attr-for-selected="name" id="page">
<my-iron-list name="view1" scroll-target="[[_getScrollTarget()]]"></my-iron-list>
<my-view2 name="view2"></my-view2>
<my-view3 name="view3"></my-view3>
</iron-pages>
</app-header-layout>
I looked into the implementation of app-header-layout to find the right element. This expression actually yields me the right element and everything works fine.
_getScrollTarget: function() {
return this.$.layout.shadowRoot.querySelector("#contentContainer");
}
But there has to be a better, a right way? Grabbing into the shadow DOM of the app-header-layout is not exactly using "public interface"!
To complete the example, here my code for my-iron-list. My-iron-list wraps and iron-list, iron-scroll-theshold, and some dummy data provider stuff. The scroll-target on my-iron-list is just passed to the iron-list and iron-scroll-threshold within my-iron-list:
<dom-module id="my-iron-list">
<template>
<iron-list items="[]" as=item id="list" scroll-target="[[scrollTarget]]">
<template>
<div class="item">[[item]]</div>
</template>
</iron-list>
<iron-scroll-threshold
id="scrollTheshold"
lower-threshold="100"
on-lower-threshold="_loadMoreData"
scroll-target="[[scrollTarget]]">
</iron-scroll-threshold>
</template>
<script>
Polymer({
is: 'my-iron-list',
properties: {
page: {
type : Number,
value : 0
},
perPage: {
type : Number,
value : 100
},
scrollTarget: HTMLElement,
},
_pushPage: function() {
for (i = 0; i < this.perPage; i++) {
this.$.list.push('items', 'Entry number ' + (i+1+this.page*this.perPage));
}
},
_loadMoreData: function() {
this._pushPage();
this.page = this.page + 1;
this.$.scrollTheshold.clearTriggers();
}
});
</script>
</dom-module>
I have the same problem as you, for now the cleanest anwser I have was to use the app-header scrollTarget.
In your case move add an id to the app-header
<app-header condenses reveals effects="waterfall" id="header">
<app-toolbar>
<paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
<div title>Twiamo</div>
</app-toolbar>
</app-header>
and then instead of
_getScrollTarget: function() {
return this.$.layout.shadowRoot.querySelector("#contentContainer");
}
just use the scrollTarget property
_getScrollTarget: function() {
return this.$.header.scrollTarget;
}
If you found out a better way let me know.
Cheers,
I struggled with the same issue. While I was using iron-scroll-target-behavior instead of iron-scroll-threshold, I still needed to pass a scroll-target reference to an element inside a app-layout-header.
If has-scrolling-region is true, app-header-layout sets the scroll-target to be an internal div with an ID of #contentContainer. You can target this div and pass it as the scroll-target to your iron-list.
You would just need to alter the _getScrollTarget function inside your original code.
_getScrollTarget: function() {
return this.$.layout.$.contentContainer;
}
Hope it helps!
If anyone is coming here for an answer in 2017, I'm just letting you know that the same issue persists in Polymer 2.0.
I was able to overcome the issue by having the following code in my app shell (eg. PSK's my-app.html):
First, put an id attribute of 'layout' on your app-header-layout element.
Next, add this to your Polymer class (in your my-app.html equivalent):
static get properties() {
return {
scrollTarget: HTMLElement,
}
}
ready() {
super.ready();
this.scrollTarget = this.$.layout.shadowRoot.querySelector("#contentContainer");
}
Then, pass in the property to a scroll-target attribute on your lazy-loaded pages:
<my-page scroll-target="[[scrollTarget]]"></my-page>
Finally, in your lazy-loaded pages (eg. my-page):
<iron-list scroll-target="[[scrollTarget]]"></iron-list>
...
static get properties() {
return {
scrollTarget: HTMLElement,
}
}
This isn't an ideal solution, but it works.

Polymer 1.0 paper-drawer-panel call function when drawer closes

I have a paper-drawer-panel that has a closed drawer. When I click a fab I open the drawer and hide the fab. However when the drawer closes again I would like to re-show the fab.
My question is this: How do I know when the drawer is closing?
I looked into the two events listed in the paper-drawer-panel docs and tried both paper-select and paper-responsive-change. I used them in the following way:
html:
<paper-drawer-panel right-drawer force-narrow narrow paper-select="changed">
<div main> content... </div>
<div drawer> drawer content </div>
</paper-drawer-panel>
js:
changed:function(){
console.log("inside event");
}
should this work? can anyone offer some suggestions?
As I mentioned in the comment, I solved this by using TrevorDixon's advice and changing paper-select to on-iron-select
http://jsbin.com/winedi/edit?html,output
menuToggle: function() {
if (this.$.paper_drawer_panel.narrow && $(this.$.paper_drawer_panel).width() < parseInt(this.$.paper_drawer_panel.responsiveWidth)) {
this.$.paper_drawer_panel.togglePanel();
} else {
this.$.paper_drawer_panel.forceNarrow = !this.$.paper_drawer_panel.forceNarrow;
}
}
took from Polymer 1.0 paper-drawer-panel toggle is not working

How can polymer put a list of checkboxes in the left panel?

I'm trying to learn Polymer and I'm stuck. My goal is to put a list of checkboxes in the drawer panel on the left using core-list (the choices are dynamic, the server sends JSON in the page [no AJAX in this case]). Here's what I have:
<core-scaffold>
<core-header-panel navigation fit mode="seamed">
<core-toolbar>Left Header</core-toolbar>
<div fit style="overflow:auto;">
<core-list id="list" data="{{CheckboxList}}" flex multi>
<template>
<div class="row {{ {selected: selected} | tokenList }}">
Go
List row: {{index}}, Name: {{model.Name}}, Title: {{model.Title}}
<input type="checkbox" checked="{{model.Selected}}">
</div>
</template>
</core-list>
</div>
</core-header-panel>
<div tool>Right Panel Title</div>
<div vertical layout>
stuff...
</div>
</core-scaffold>
The div wrapping the list was intended to get rid of the following error, without success:
core-list must either be sized or be inside an overflow:auto div that is sized
I've wrapped this list every way I can think of to give it a size, and can't seem to shake this error message.
I'm also concerned because the docs said that core-list doesn't render the entire list, only a visible view of elements. This is a problem for checkboxes, since this needs to eventually submit a form with the checked values. Is there a way to override this functionality and force it to render the entire list, or is there an alternative to core-list that is better suited for repeating elements that must be rendered?
You may try using style="height:100%" as a core-list attribute. I recall Rob Dodson mentioning that the core-list explicitly needs to be given a height. By doing so I could get rid of the error you mentioned. Here is the jsfiddle and snipped:
http://jsfiddle.net/kreide/zt5xmoa9/
<link rel="import" href="http://www.polymer-project.org/components/polymer/polymer.html">
<link rel="import" href="http://www.polymer-project.org/components/paper-elements/paper-elements.html">
<link rel="import" href="http://www.polymer-project.org/components/core-elements/core-elements.html">
<polymer-element name="my-element" constructor="" attributes="">
<template>
<style>
.selected {
background: silver;
}
</style>
<core-scaffold>
<core-header-panel navigation fit mode="seamed">
<core-toolbar>Left Header</core-toolbar>
<div fit style="overflow:auto;">
<core-list id="list" data="{{CheckboxList}}" style="height:100%;" flex multi>
<template>
<div class="row {{ {selected: selected} | tokenList }}">
Go
List row: {{index}}, Name: {{model.Name}}, Title: {{model.Title}}
<input type="checkbox" checked="{{model.Selected}}">
</div>
</template>
</core-list>
</div>
</core-header-panel>
<div tool>Right Panel Title</div>
<div vertical layout>
stuff...
</div>
</core-scaffold>
</template>
<script>
Polymer('my-element', {
CheckboxList: [{"Name": "1", "Title": "1" }, {"Name": "2", "Title": "2" }, {"Name": "3", "Title": "3" }]
});
</script>
</polymer-element>
<my-element></my-element>
PS: I have no answer to your last question though, as I am not sure about rendering behaviour of core-list. core-menu might be an alternative as it is derived from core-selector and might act different from core-list. But these are just guesses, not an answer.
I think in response to your last question, you should bind the checkbox's check state to an attribute on the data used to render the core-list. This allows the core-list to separate its presentation from the state of the values that you keep in the list. Then, you can use that data in your ECMAscript model to perform actions or submit to a URI.
The demo for core-list shows data-binding to a number of different kinds of input elements.
I had the same issue and my solution was pretty simple. For:
<section route="home" id="home">
<div fit class="div-core-list">
<core-list data="{{data}}" flex>
<template>
<div class="row">
<div>{{model.name}}</div>
</div>
</template>
</core-list>
</div>
</section>
I've used the css code:
.div-core-list {
overflow: auto;
height: 300px; /* can be any value in px*/
}
core-list {
height:100%;
}
I hope it helps.