How to change app route location from child element - polymer

I created app-route based project. Certain event I need to change the route to different root.
index.html
<my-app></my-app>
my-app.html
<!-- this app-route manages the top-level routes -->
<app-route
route="{{route}}"
pattern="/:view"
data="{{routeData}}"
tail="{{subroute}}"></app-route>
<!-- iron-pages selects the view based on the active route -->
<iron-pages selected="[[routeData.view]]" attr-for-selected="name">
<landing-app name="home" route="{{subroute}}"></landing-app>
<dashboard-app name="dashboard" route="{{subroute}}"></dashboard-app>
</iron-pages>
landing-app.html
When handler called I need to change the route to dashboard. How to do that ?
<dom-module id="landing-app">
<template>
<button on-click="_handlerCall">Change to Dashboard</button>
</template>
<script>
class LandingApp extends Polymer.Element {
static get is() {return 'landing-app'}
_handlerCall() {
this.set('route.path', '/dashboard') // but no luck :(
}
}
customElements.define(LandingApp.is, LandingApp);
</script>
</dom-module>

Add:
<app-location route="{{route}}"></app-location> after <template> in landing-app.html
<dom-module id="landing-app">
<template>
<app-location route="{{route}}"></app-location>
<button on-click="_handlerCall"> Change to Dashboard</button>
</template>
<script>
class LandingApp extends Polymer.Element {
static get is() {return 'landing-app'}
_handlerCall() {
this.set('route.path', '/dashboard') // :)
}
}
customElements.define(LandingApp.is, LandingApp);
</script>
</dom-module>
Documentation for app-location:
https://www.webcomponents.org/element/PolymerElements/app-route/elements/app-location

Related

Vaadin 10 slot in vaadin-dialog

I want to create a reusable dialog in Vaadin 10. Therefore I thought of using the tag in vaadin-dialog. I created a html file containing the templated vaadin-dialog.
<dom-module id="show-sera-dialog">
<template>
<vaadin-dialog opened="opened">
<sera-field></sera-field>
<slot></slot>
</vaadin-dialog>
<template>
</dom-module>
And I try to use it like this.
<show-sera-dialog opened="{{showSera}}">
It worked!
</show-sera-dialog>
The dialog will be opened and the sera-field displayed, but the text is never displayed. Is there an error withing these lines? Am I using vaadin-dialog the wrong way?
PS:
It works with this button:
<dom-module id="one-shot-button">
<template>
<vaadin-button on-click="_disable" theme="raised primary" disabled={{disabled}}>
<slot></slot>
</vaadin-button>
</template>
<script>
class OneShotButton extends I18nMixin(Polymer.Element) {
static get is() {
return 'one-shot-button'
}
static get properties() {
return {
disabled: {type: Boolean, notify: true}
}
}
_disable() {
this.disabled = true;
this.onClick();
}
}
customElements.define(OneShotButton.is, OneShotButton);
</script>
You are putting a <slot> inside a <template>. Template means that web component will do whatever it needs when rendering it, e.g. by creating multiple instances like cells in grid, etc.
In this case vaadin-dialog teleports the content to the body, so as it escapes any stacking context. Thus it makes slots not work because they are not in the same DOM hierarchy.
One way to create a reusable dialog would be to create a component like this
<dom-module id="show-sera-dialog">
<template>
<vaadin-dialog opened={{opened}}>
<template>
[[text]]
</template>
</vaadin-dialog>
</template>
<script>
class ShowSeraDialog extends Polymer.Element {
static get is() { return 'show-sera-dialog'; }
static get properties() {
return {
"text" : String,
"opened" : Boolean
}
}
}
window.customElements.define(ShowSeraDialog.is, ShowSeraDialog);
</script>
</dom-module>
And use it like this
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="./show-sera-dialog.html">
<dom-module id="polymer-test-app">
<template>
<show-sera-dialog id="dialog1" text="It worked!"></show-sera-dialog>
<button on-click="showDialog">Show dialog</button>
</template>
<script>
class PolymerTestApp extends Polymer.Element {
static get is() { return 'polymer-test-app'; }
showDialog() {
this.$.dialog1.opened = true;
}
}
window.customElements.define(PolymerTestApp.is, PolymerTestApp);
</script>
</dom-module>

Polymer dom-if not re-firing

I have been having problems with my Polymer 2 app, I first through it was the routing but I found that after hitting this page and the Dom-if fires when navigating back to the page it is not re-firing.
EG,
If I am on url/matters/6719 it displays the details page, but if I click the back button and go to url/matters the dom-if is not being hit again and its still showing me the details page,
It also happens when using my navigation selector which is set up like the PWA starter kit.
<link rel="import" href="../bower_components/polymer/polymer-element.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="import" href="../bower_components/iron-pages/iron-pages.html">
<link rel="import" href="../bower_components/iron-selector/iron-selector.html">
<link rel="import" href="shared-styles.html">
<link rel="import" href="Matters/matter-list.html">
<link rel="import" href="MatParties/matparty-list.html">
<link rel="lazy-import" href="Matters/matter-detail.html">
<dom-module id="my-matters">
<template>
<style include="shared-styles">
:host {
display: block;
padding: 10px;
}
</style>
<app-route route="{{route}}" pattern="/:matter_id" data="{{routeData}}" tail="{{subroute}}">
<app-route route="{{subroute}}" pattern="/matparties/:this_page" data="{{pageData}}"></app-route>
</app-route>
<div class="card">
<template is="dom-if" if="[[_subidIsDefined(pageData.this_page)]]">
<matparty-list linkedmatpartyid="[[pageData.this_page]]"></matparty-list>
</template>
<template is="dom-if" if="[[!_subidIsDefined(pageData.this_page)]]">
<template is="dom-if" if="[[!_idIsDefined(routeData.matter_id)]]">
<matter-list></matter-list>
</template>
<template is="dom-if" if="[[_idIsDefined(routeData.matter_id)]]">
<matter-detail linkedmatterid="[[routeData.matter_id]]"></matter-detail>
</template>
</template>
</template>
<script>
class Matters extends Polymer.Element {
static get is() { return 'my-matters'; }
_subidIsDefined(subid) {
//There are probably ways to optimize this
if (subid) {
return true;
}
return false;
}
_idIsDefined(id) {
//There are probably ways to optimize this
if (id) {
return true;
}
return false;
}
}
window.customElements.define(Matters.is, Matters);
</script>
</dom-module>
have you checked the pattern? Normally the pattern should respect the url pattern.... in your case "url/matters/6719"
Since you have defined the pattern="/matparties/:this_page" on the router and matparties is != 'matters' in 'url/matters/6719' that could generate the error. I don't know if you have defined a base url that generate also some issues on this regards.
So the url should be matparties/6719 to match the pattern and resolve into the dom-if

How to handle vaadin-grid events in custom polymer 2 element?

I need to include a vaadin-grid in a custom Polymer 2 element and need to handle the row selection event, but I can't seem to get it to work. I've managed to cobble together this from the various starter templates and demos on offer, and the basic click event handler works, but I have no idea how to handle the row selection. I'm actually using v3.0.0-beta1 of the vaadin-grid because I couldn't get v2 to work, but I don't think that's my problem.
Does anyone know how to handle events in vaadin components when you include them in your own custom elements?
Thanks.
<link rel="import" href="bower_components/polymer/polymer-element.html">
<link rel="import" href="bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="bower_components/vaadin-grid/vaadin-grid.html">
<dom-module id="my-element">
<template>
<style>
:host {
display: block;
}
</style>
<iron-ajax auto url="https://demo.vaadin.com/demo-data/1.0/people?count=200" handle-as="json" last-response="{{users}}"></iron-ajax>
<vaadin-grid aria-label="My Test Grid" items="[[users.result]]" id="grid">
<vaadin-grid-column width="50px" flex-grow="0">
<template class="header">#</template>
<template>[[index]]</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template class="header">First Name</template>
<template>[[item.firstName]]</template>
</vaadin-grid-column>
<vaadin-grid-column>
<template class="header">Last Name</template>
<template>[[item.lastName]]</template>
</vaadin-grid-column>
<vaadin-grid-column width="150px">
<template class="header">Address</template>
<template>
<p style="white-space: normal">[[item.address.street]], [[item.address.city]]</p>
</template>
</vaadin-grid-column>
</vaadin-grid>
</template>
<script>
class MyElement extends Polymer.Element {
static get is() { return 'my-element'; }
ready() {
super.ready();
this.$.grid.addEventListener('click', e => {
this._handleClick(e)
});
// I added this listener code from here: https://vaadin.com/elements/-/element/vaadin-grid#demos
// but it does nothing. I've also tried adding it to this, this.$, this.$.grid without success.
// Should this event listener be added here, or if not, where exactly? The docs are very unclear.
addEventListener('WebComponentsReady', function() {
Polymer({
is: 'my-element',
properties: {
activeItem: {
observer: '_activeItemChanged'
}
},
_activeItemChanged: function(item) {
this.$.grid.selectedItems = item ? [item] : [];
console.info('row clicked');
}
});
// this works and outputs info like this: "vaadin-grid-cell-content-17 was clicked."
_handleClick(e) {
console.info(e.target.id + ' was clicked.');
}
}
window.customElements.define(MyElement.is, MyElement);
</script>
</dom-module>
I think that my code in the addEventListener is Polymer 1.x syntax but I'm not sure how to achieve the same result using Polymer 2.x.
I used only vaadin-grid v2, but I downloaded the v3.0.0-beta1 and took a look inside the package, at demo/row-details.html
There is an example on how to handle the active row change event.
<vaadin-grid on-active-item-changed="_onActiveItemChanged" id="grid" aria-label="Expanded Items Example" data-provider="[[dataProvider]]" size="200">
<template class="row-details">
<div class="details">
<img src="[[item.picture.large]]"></img>
<p>Hi! My name is [[item.name.first]]!</p>
</div>
</template>
</vaadin-grid>
You can then define a function called _onActiveItemChanged inside your polymer element to handle the active item changed event.

app-router "go" is not rendering : Polymer

I am trying to replace a component on the screen using app-router element but it doesn't render anything. Below are the details.
There are two major elements in "my-element.html". One is the side bar and other is the main panel. I want to replace the main panel with appropriate element based on the route. However, it doesn't render any element but modifies the url.
Please help
my-element.html
<dom-module id ="my-element">
<template>
<paper-drawer-panel id="drawerpanel">
<aq-sidebar></aq-sidebar>
<app-router div="app-router" mode="hash">
<app-route path="/editor" import="../layouts/editor.html"></app-route>
<app-route path="/analyze" import="../layouts/analyze.html"></app-route>
<app-route path="/community" import="../layouts/community.html"></app-route>
</app-router>
</paper-drawer-panel>
</template>
<script>
Polymer({ is:'my-element',
listeners: {'change-menu': 'menuChanged',},
menuChanged(newMenu) { this.$$('app-router').go("/editor", {replace:true});}
})
</script> </dom-module>
aq-sidebar.html
<dom-module id='aq-sidebar'>
<template>
<paper-header-panel class='sidenav fit'>
<paper-toolbar>
<div class="title">AimsQuant</div>
<paper-icon-button icon="icons:menu" on-tap="toggleMenu"></paper-icon-button>
</paper-toolbar>
<paper-menu attrForSelected="data-panel" iron-select="onSelected">
<paper-icon-item noink data-panel="editor">
<iron-icon item-icon icon="vaadin-icons:twin-col-select"></iron-icon>
<span class="item-text">Editor</span>
<!--a is="pushstate-anchor" href="#/editor"></a-->
</paper-icon-item>
<paper-icon-item data-panel="analyze">
<iron-icon item-icon icon="vaadin-icons:chart"></iron-icon>
<span class="item-text">Analyze</span>
</paper-icon-item>
<script> Polymer({
is: 'aq-sidebar',
listeners: {
'iron-select': 'onSelected',
},
onSelected() {
this.fire('change-menu', {menu : this.menuSelected})
},
});
</script>
</dom-module>
First, this import style is strange, I do think that it would be right if you use the iron-selector to switch between the view components that you've made, and import then using the importHref function, also you should use the Set function of polymer to change the path instead of this Go function. like this:
<app-location route="{{ route }}"></app-location>
<app-route route="{{ route }}"
pattern="/:page"
data="{{ routeData }}"
tail="{{ subroute }}"></app-route>
<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)"
],
_changeRoute: function(e) {
this.importHref(
this.resolveUrl("my-" + e.detail.requestRoute), null, null, true);
this.set("route.path", e.detail.requestRoute);
},
_routePageChanged: function(page) {
this.page = page || "list";
},
})
</script>

how to inject <template> into polymer component by providing it as element content

i want to inject a template into an polymer component like this :
<polymer-element name="foo-bar">
<template>
<content></content>
<!-- content is expected to contain a template with id="layout"-->
<template bind ref="layout">
default content template
</template>
</template>
<script src="index.js"></script>
</polymer-element>
usage of the component :
<foo-bar>
<template id="layout">another content template</template>
</foo-bar>
unfortunately the template provided as content of the element is not taken over for some reason.
when simluate the wished behaviour using
<polymer-element name="foo-bar">
<template>
<template id="layout">
custom content template
</template>
<template bind ref="layout">
default content template
</template>
</template>
<script src="index.js"></script>
</polymer-element>
the referenced template(id="layout") is used as expected.
Any help is appreciated :-)
<template ref="layout"> says use the template#layout for my content. So I would expect the template in your shadow dom to use the content of the light dom template. This is what you see in http://jsbin.com/takipi/1/edit.
However, if you want to use render the light dom <template> the user provides, you must activate it using template.createInstance(). By default, templates are inert. For this use case, you also don't need <content>. That's for rendering and in this case, it doesn't really make sense.
The example below also show how to set things up. It also shows how you can use {{}} bindings in the light dom <template> and fill them when the instance is created.
<div id="container"></div>
<template if="{{showDefault}}">
default content template
</template>
attached: function() {
var template = this.querySelector('template');
if (template) {
this.$.container.appendChild(
template.createInstance({foo: 5}));
this.showDefault = false;
}
}
Full code:
<script src="http://www.polymer-project.org/platform.js"></script>
<script src="http://www.polymer-project.org/polymer.js"></script>
<polymer-element name="foo-bar">
<template>
<div id="container"></div>
<template if="{{showDefault}}">
default content template
</template>
</template>
<script>
Polymer({
showDefault: true,
attached: function() {
var template = this.querySelector('template');
if (template) {
// Allow Polymer expressions in the template's {{}}.
if (!template.bindingDelegate) {
template.bindingDelegate = this.element.syntax;
}
this.$.container.appendChild(
template.createInstance({foo: 5}));
this.showDefault = false;
}
}
});
</script>
</polymer-element>
<foo-bar>
<template>
<b>another</b> content template. Also supports data: {{foo}}
</template>
</foo-bar>