href to another element does not work in Polymer - html

I created a project using the Polymer Starter Kit, with its app-router.
My my-app.html has the selectors for the views like so..
<iron-pages role="main" selected="[[page]]" attr-for-selected="name">
<my-view1 name="view1"></my-view1>
<my-view2 name="view2"></my-view2>
<my-view3 name="view3"></my-view3>
<my-view4 name="view4"></my-view4>
<my-view5 name="view5"></my-view5>
<my-view6 name="view6"></my-view6>
</iron-pages>
I have a component my-view1.html, within which I have div with href tag
<div>God 1 Jump to example </div>
elsewhere in the document I have
<p id="gotogod">
God is great
</p>
While I dont get any errors, it doesnt jump to the paragraph when I click the link. When I hover over the link, I do get
http://localhost:8080/view1#gotogod
But the page doesnt jump to that spot.
I have tried various combinations for the href without luck.
Please help.

HTML Element:
<a on-click="scrollIntoView" section-id="gotogod">
Javascript Function:
scrollIntoView(e) {
let sectionId = e.target.getAttribute('section-id');
this.$[sectionId].scrollIntoView();
}

Ok, you need to be alert about the app-route, when you're going to change the route, you should change it by the app-route.
I do it (kind of) this way:
<app-location route="{{ route }}"></app-location>
<app-route route="{{ route }}"
pattern="/:page"
data="{{ routeData }}"
tail="{{ subroute }}"></app-route>
<iron-selector attr-for-selected="route"
selected="[[ page ]]"
role="navigation">
<a route="editor" href="/editor">Editor</a>
<a route="analyze" href="/analyze">Analyze</a>
<a route="community" href="/community">Community</a>
</iron-selector>
<iron-pages role="main"
attr-for-selected="route"
selected="[[ page ]]">
<my-editor route="editor"></my-editor>
<my-analyze route="analyze"></my-analyze>
<my-community route="community"></my-community>
</iron-pages>
<script>
Polymer({
is:'my-element',
properties: {
page: {
type: String,
notify: true,
reflectToAttribute: true,
observer: "_pageChanged"
}
},
observers: [
"_routePageChanged(routeData.page)"
],
listeners: {
"requestChangeRoute": "_changeRoute"
},
attached: function(e) {
// Lazyload the views as soon as the AppShell has been Painted
this.importHref(
this.resolveUrl("my-editor.html"), null, null, true);
this.importHref(
this.resolveUrl("my-analyze"), null, null, true);
this.importHref(
this.resolveUrl("my-community"), null, null, true);
// If the application is reloaded, redirect to /analyze
if(this.page != "analyze"){
this.set("route.path", "/analyze");
}
},
_changeRoute: function(e) {
this.set("route.path", e.detail.requestRoute);
},
_routePageChanged: function(page) {
this.page = page || "analyze";
}
})
</script>
On the main page, where the route is defined, you can use the href with route to navigate, but when you're inside some of your page elements, where there isn't the app-route defined, you should ask for you main page to change the route by the app-route using the function _changeRoute without href, this call is made like this:
this.fire("requestChangeRoute", {
route: "/editor"
});
This way you have sure that the app-route is taking care of the navigation and that every page is going to work, and you can even set validations or parameters to be passed by this function.

It seems that this answer is what you look for :
Polymer scroll to a specific div
You can do :
<a href="#gotogod" class="link" on-click="_goToGoScroll">
And in the code of the Polymer element :
_goToGoScrool() {
this.$.gotogod.scrollIntoView();
}

Related

Polymer app-route redirect via function issue

just when I thought I figured out how app-route is working, I run into an issue that let me doubt that my understanding of this element is correct.
From what I understood, it's the responsibility of app-location to keep the browser URL and the value of route in sync. If one of them changes app-location takes care that the other one is changing as well.
And because the route attribute of app-route, is in sync with it's data attribute, changes of the data attribute by the paper-tabs in the code below causes a change in the route attribute of app-route causes the app-location to update the browser URL.
However since I didn't use the fallback-selection attribute in paper-tabs the surfing to http://localhost will set the path to '/' and therefore not showing the home-page.
So I thought I could redirect the URL with the code in the ready function. But unfortunately the route.path indeed changes but the URL doesn't.
Why is that? What do I have to do to redirect the route manually via a function?
Or in other words: Why does a change of routeData.subpage via the paper-tabs element causes a redirect, and a change of routeData.subpage from the function not?
<dom-module id="polymer-app">
<template>
<style>
:host {
display: block;
}
</style>
<app-location route="{{route}}"></app-location>
<app-route id="ar"
route="{{route}}"
pattern="/:subpage"
data="{{routeData}}"
tail="{{routeTail}}"
active="{{routeActive}}">
</app-route>
<header>
<paper-tabs attr-for-selected="name" selected="{{routeData.subpage}}">
<paper-tab name="home">Home</paper-tab>
<paper-tab name="settings">Settings</paper-tab>
</paper-tabs>
</header>
<section id="main">
<iron-pages attr-for-selected="name" selected="[[routeData.subpage]]">
<home-page name="home"></home-page>
<settings-page name="settings"></settings-pagina>
</iron-pages>
</scection>
</template>
<script>
Polymer({
is: 'polymer-app',
properties: {
route: Object,
routeData: Object,
routeTail: Object,
routeActive: Boolean,
},
ready: function() {
if (this.route.path == "/") {
this.set('routeData.subpage', 'home');
console.log(this.routeData);
console.log(this.route);
}
},
});
</script>
</dom-module>
Add a page property with an observer that will either assign it the current value (based on the URL) or a default value if the URL path is empty
static get properties() {
return {
page: {
type: String,
reflectToAttribute: true,
observer: '_pageChanged',
},
}
static get observers() {
return [
'_routePageChanged(routeData.page)',
];
}
_routePageChanged(page) {
// If no page was found in the route data, page will be an empty string.
// Default to 'home' in that case.
this.routeData.subpage = page || 'home';
}

Polymer href link anchor does not scroll to div when using <iron-pages>

I'm using Polymer 1.x, and I have an <iron-selector> with generated links. I would like for one of my links to scroll to a <div>. However, I cannot achieve this successfully as the link is intercepted by the <iron-pages>. Here is what I have tried so far:
<app-location route="{{route}}"></app-location>
<app-route
route="{{route}}"
pattern="/:page"
data="{{routeData}}"
tail="{{subroute}}"></app-route>
<iron-selector role="navigation" class="drawer-list" selected="[[categoryName]]" attr-for-selected="name">
<template is="dom-repeat" items="[[categories]]" as="category" initial-count="4">
<a name="[[category.name]]" href="[[category.link]]">[[category.title]]</a>
</template>
</iron-selector>
<section id="contactSection" class="home-contact ss-style-triangles">
<div class="container">
<div class="contact-wrap">
<h1>Contact</h1>
</div>
</div>
</section>
<iron-pages role="main" selected="[[page]]" attr-for-selected="name" selected-attribute="visible" fallback-selection="404">
<!-- home view -->
<cass-home name="home"></cass-home>
<cass-why name="whyChooseUs" route="{{subroute}}"></cass-why>
<cass-partner name="partner" route="{{subroute}}"></cass-partner>
<cass-404-warning name="404"></cass-404-warning>
</iron-pages>
Then in JavaScript:
var categoryList = [
{
name: 'home',
title: 'Accueil',
link: '/home',
},
{
name: 'home',
title: 'Home',
link: '/home',
},
{
name: 'b2b',
title: 'Company',
link: '/b2b',
},
{
name: 'login',
title: 'Connection',
link:'/login'
},
{
name: 'contact',
title: 'Contact',
link:'javascript:document.querySelector("#contactSection").scrollIntoView();'
}
];
The is linked to an to set the core part of my
However, as it is in the local DOM, it's not detecting the #contactSection. I also tried using a function and registering a listener, but unsuccessfully.
Any hints?
You can workaround that problem by imperatively scrolling the <div> into view with a listener on the anchor's tap event:
About
Contact
// <script>
_onTapAnchor: function(e) {
e.preventDefault();
var anchor = e.target.attributes.href.value;
this.$$(anchor).scrollIntoView();
}
Notes:
e.target is the <a> tag, which has an attributes map, containing the raw value of href (#contactSection as opposed to http://localhost:8080/#contactSection).
We take e.target.attributes.href.value (e.g., #contactSection) and query the local DOM for it with this.$$(...) -- shorthand for Polymer.dom(this.root).querySelector(...).
We then take the result of the previous call (which is a <div>), and call scrollIntoView() on it, which brings the <div> into the viewport.

Polymer deactivating pages when their not in view

I'm using the polymer application drawer template from the polymer cli.
I'm having some trouble with:
When you load a new page, the html element is imported; then it's code executes
When I move to another page the code for the previous page is still running.
Is there a way to destroy and create the page/element or suspend and enable?
Whats the best practice for dealing with this problem?
Have the pages implement a create and destroy method and invoke it when changing page?
Ie
oldPageElement.destroy();
newPageElement.create();
Polymer({
is: 'my-random-page',
behaviors: [MyBehaviors.CommonPageBehavior],
/**
* #override
*/
create: function() {..}
/**
* #override
*/
destroy: function() {..}
})
You actually don't need to implement anything complicated, but just use a mere dom-if.
Working prototype: http://jsbin.com/gezihatera/edit?html,console,output
As you can see, the "View One" uses a custom page element, which is always restamped when re-selected. Other pages are ordinary div elements, since this is only a minimal prototype. But this also shows that you can selectively choose which pages get restamped and which do not (if you don't always need this).
The essence is the following: as per dom-if documentation, if you set the restamp attribute to true, then the dom-if will always create and destroy your pages upon selecting/deselecting them. You can see this in the console, where I print out sample-page ready on every ready element. I also create a helper function _equals to help with comparing whether the specified page is really selected.
To sum up, let me paste the code for the app:
<dom-module id="sample-app">
<template>
<style>
:host {
display: block;
}
</style>
<iron-selector selected="{{page}}" attr-for-selected="name">
<a name="view1" href="#">View One</a>
<a name="view2" href="#">View Two</a>
<a name="view3" href="#">View Three</a>
</iron-selector>
<iron-pages role="main" selected="[[page]]" attr-for-selected="name">
<template is="dom-if" if="[[_equals(page, 'view1')]]" restamp="true">
<sample-page name="view1">view1</sample-page>
</template>
<div name="view2">view2</div>
<div name="view3">view3</div>
</iron-pages>
</template>
<script>
Polymer({
is: 'sample-app',
_equals: function(a, b) {
return a == b;
},
});
</script>
</dom-module>
And the code for the sample page:
<dom-module id="sample-page">
<template>
<style>
:host {
display: block;
}
</style>
<content></content>
</template>
<script>
Polymer({
is: 'sample-page',
ready: function() {
console.log('sample-page ready');
},
});
</script>
</dom-module>
Hope this satisfies your question.
Note: you should not put the name attribute on the dom-if itself, but rather onto its content (the same way I did).
Thought I would post my solution after implementing #alesc's dom-if to get the element to be deactivated.
// after a successful importHref, _pageLoaded is called.
_pageLoaded: function(pageName) {
var name = 'my-' + pageName;
this.async(function() {
// async to wait for element restamping, if done
var pages = this.$.pages;
var page = pages.querySelector(name);
page.load()
.then(page.isAuthorized.bind(this))
.catch(this._catchPageIsAuthorizedError.bind(this))
.then(this._shouldSetPage.bind(this, pageName));
}.bind(this));
}

How to properly bind iron-selector to iron-pages?

I am trying to do the same basic task as this other question, iron-selector selected={{}} binding with iron-pages selected={{}}, but I believe my case must be different, since I cannot replicate the solution.
I want to have a menu of buttons with iron-selector, and when clicked, the content with iron-pagesshould change.
So I have the actual page about.htm that has 1 webcomponent for the button-menu, called about-buttons.htm and then 1 webcomponent for each page, that should load according to which button is pushed by the user; about-who.htm, about-manifesto and about-team.
My question is:
How can I with this structure of my web components bind my buttons with my pages - and / or why is my current method wrong?
There's a lot of different ways to do a simple data binding like this. My method here is definitely not simple, and it does not work (by clicking buttons, the pages does not change).
So my about.htm looks like this (and this is the page people will visit):
<about-buttons selected="{{who}}">
</about-buttons>
<about-iron-pages attr-for-selected="name" selected="{{who}}" fallback-selection="who">
<about-us name="who">
</about-us>
<about-manifesto name="manifesto">
</about-manifesto>
<about-team name="team">
</about-team>
</about-iron-pages>
My about-buttons.htm looks like this:
<iron-selector
attr-for-selected="name"
selected="{{buttonSelected}}"
fallback-selection="who"
class="f-column f-column_3 f-column_mobile_2">
<button class="f-button-group__button" name="manifesto">Manifesto</button>
<button class="f-button-group__button" name="who">Who we are</button>
<button class="f-button-group__button" name="team">Team</button>
</iron-selector>
With this script:
<script>
Polymer({
is: 'about-buttons',
properties: {
buttonSelected: {
type: String,
notify: true,
value: 'who'
}
}
});
</script>
And here's my version of iron-pages:
<dom-module id="about-iron-pages">
<template>
<style>
:host {
display: block;
}
:host > ::content > :not(.iron-selected) {
display: none !important;
}
</style>
<content>
</content>
</template>
<script>
Polymer({
is: 'about-iron-pages',
behaviors: [
Polymer.IronResizableBehavior,
Polymer.IronSelectableBehavior
],
properties: {
activateEvent: {
type: String,
value: null,
}
},
observers: [
'_selectedPageChanged(selected)'
],
_selectedPageChanged: function(selected, old) {
this.async(this.notifyResize);
}
});
</script>
</dom-module>
As already pointed out, your attribute in <about-buttons selected="..."> does not match the actual property name. For <about-buttons>.buttonSelected, your attribute should be button-selected, and that's the only change to your code needed to get the selector working (plunker):
<about-buttons button-selected="{{who}}" ...>
Perhaps there's more context to your need for <about-buttons> and <about-iron-pages>, but otherwise, if you're only trying to implement a tabbed view, you could just use Polymer's components.
Specifically, <about-buttons> could be replaced by <paper-tabs> and <about-iron-pages> by <iron-pages> (plunker).

How do I put the selected core-menu item into a custom polymer element?

I'm trying to encapsulate a paper-dropdown in a paper-button. To do this, I made a custom element, paper-dropdown-holder:
<polymer-element name="paper-dropdown-holder" extends="paper-button" relative on-tap="{{toggle}}">
<template>
<shadow></shadow>
<content></content>
</template>
<script>
Polymer({
toggle: function() {
if (!this.dropdown) {
this.dropdown = this.querySelector('paper-dropdown');
}
this.dropdown && this.dropdown.toggle();
}
});
</script>
</polymer-element>
and I'm using it in the page like:
<paper-dropdown-holder raised tabindex="0" class="unpadded">
<paper-dropdown class="dropdown" flex>
<core-menu class="menu" selected="0">
<paper-item>Writing</paper-item>
<paper-item>Blog</paper-item>
<paper-item>Art</paper-item>
</core-menu>
</paper-dropdown>
</paper-dropdown-holder>
My problem is deciphering The documentation to figure out how to automatically put the text of the currently-selected menu item into the paper-dropdown-holder.
My first attempt was to just use a standard paper-dropdown-menu, but I couldn't as easily style that like a paper-button. Is there any way to do this that's not (for lack of a better term) hacky? I'd love if the answer would keep to the Polymer philosophies.
Bonus challenge: How do I set default text like "choose section"?
One of awesome things of Polymer is it's open source... that said you could learn how to implement new element based on already existing elements....
If you have a look at paper-dropdown-menu source you could easily make something like it but with paper-button as a "control".
So
The new element should extend core-dropdown-base not
paper-button.
To make that element logically working you could do that with
some help of paper-dropdown-menu by binding (core-overlay-open,
core-activate, core-select) events to the according handlers.
(the actual binding happens in core-dropdown-base in dropdown
getter which called inside attached event listener.
To put them together:
<polymer-element name="paper-dropdown-holder" extends="core-dropdown-base" relative>
<template>
<div>
<paper-button raised on-tap="{{toggle}}">{{selectedItemLabel || label}}</paper-button>
<content></content>
</div>
</template>
<script>
Polymer('paper-dropdown-holder', {
publish: {
label: 'Select an item',
},
selectedItemLabel: '',
overlayListeners: {
'core-overlay-open': 'openAction',
'core-activate': 'activateAction',
'core-select': 'selectAction'
},
activateAction: function(e) {
this.opened = false;
},
selectAction: function(e) {
var detail = e.detail;
if (detail.isSelected) {
this.selectedItemLabel = detail.item.label || detail.item.textContent;
} else {
this.selectedItemLabel = '';
}
}
});
</script>
</polymer-element>
Demo.