I am playing around with the Polymer Starter Kit by building a simple application which has a few pages. I would like for one of the pages to display a list of items that it loads from the server. The issue is that this list must load only when the page is visible / transitioned into. How should I notify "lazy-list" to actually begin loading data?
<iron-pages attr-for-selected="data-route" selected="{{route}}">
<section data-route="some-page">
<paper-material>
<lazy-list></lazy-list>
</paper-material>
</section>
<section data-route="another page">
<paper-material elevation="1">
...
</paper-material>
</section>
</iron-pages>
Or you can just observe route and when route === "some-page", send the refresh request to <lazy-list>?
<dom-module id="my-app">
<template>
...
<iron-pages attr-for-selected="data-route" selected="{{route}}">
<section data-route="some-page">
<paper-material>
<lazy-list id="list"></lazy-list>
</paper-material>
</section>
<section data-route="another page">
<paper-material elevation="1">
...
</paper-material>
</section>
</iron-pages>
...
</template>
<script>
Polymer({
is: "my-app",
properties: {
route: {
type: String,
observer: "routeChanged"
},
...
},
...
routeChanged: function (newval,oldval) {
if (newval === "some-page") {
this.$.list.refreshList();
}
},
...
});
</script>
</dom-module>
No new element needed.
Not sure if this is the best solution but I simply created a new element for the "Page" which wraps the section. This element listens for attribute changes and will load the list when "iron-selected" is added to the class name.
<dom-module id="some-page">
<style>
</style>
<template>
<paper-material>
<lazy-list id="list"></lazy-list>
</paper-material>
</template>
<script>
(function() {
Polymer({
is: 'some-page',
ready : function(){
},
attributeChanged : function(name, type){
if(this.getAttribute('class').includes('iron-selected')){
this.$.list.refreshList();
}
}
});
})();
</script>
</dom-module>
Related
This is an excerpt of my codes:
<template is="dom-bind">
<iron-ajax auto
url="####"
params=""
handle-as="json"
last-response="{{ajaxResponse}}"></iron-ajax>
<template is="dom-repeat" items="[[ajaxResponse.Items]]">
<div>
[[_formatDate(item.ID.N)]]
</div>
</template>
</template>
...
<script>
Polymer({
is: 'home-view',
_formatDate: function(ID) {
console.log("TEST");
return "TEST";
}
});
</script>
I am getting this Console Warning:
[Warning] [dom-bind::_annotatedComputationEffect]: – "compute method `_formatDate` not defined" (data:text/javascript;charset=utf-8,(fu…%0A, line 265, x10)
So it seems that I do not know how to define _formatDate correctly so that it is recognized by Polymer. Can someone please help?
It looks like you're correctly declaring and using _formatDate().
The warning comes from dom-bind, which is intended only for bindings in index.html, not inside dom-module. You should remove the is="dom-bind" from your top template.
<head>
<base href="https://polygit.org/polymer+1.6.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<home-view></home-view>
<dom-module id="home-view">
<template>
<template is="dom-repeat" items="[[items]]">
<div>[[_formatDate(item)]]</div>
</template>
</template>
<script>
// For cross-browser compatibility, HTMLImports.whenReady()
// needed in index.html only
HTMLImports.whenReady(function() {
Polymer({
is: 'home-view',
properties: {
items: {
type: Array,
value: function() { return ['hello', 'world']; }
}
},
_formatDate: function(id) {
console.log('id', id);
return id;
}
});
});
</script>
</dom-module>
</body>
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>
I'm running into a similar problem as this question.
However, my case is a bit different and I can't seem to get it to work. I've been playing with it for a while an no luck so far.. I need href$="{{_getProject(item.project_id)}}" to be written as "webservices/api/projects/1" but the closest thing I can get is it outputting the item.project_id without being able to concatenate with it so just the 1. I've tried various things but below is what I have most recently. Does anyone have any ideas on how I can get this to work? I'm sure it's something I'm overlooking.
<template is="dom-bind">
<iron-ajax url="<?echo $url?>" last-response="{{data}}" auto></iron-ajax>
<iron-list items="[[data]]" as="item">
<template>
<div>
<div class="item">
<div class="pad">
<div class="primary">[[item.project_name]]</div>
<div class="secondary">Project Deadline:</div>
<div class="secondary">[[item.project_deadline]</div
<div class="secondary">Total Hours to date:</div>
<div class="secondary">[[item.project_total_hours</div>
<div class="secondary">[[item.project_id]]</div>
</div>
<a href$="{{_getProject(item.project_id)}}"><iron-icon icon="assignment"><iron-icon></a>
</div>
</div>
</template>
<script>
Polymer({
_getProject: function(url) {
return 'webservices/api/projects/' + url
}
});
</script>
</iron-list>
</template>
The Polymer({...}) call you have inside of your iron-list won't work as you expect (and it should actually show an error in the console), since you are not defining/can't define a custom element inside of iron-list but only a template that will be stamped.
There are two ways to achieve what you want.
Define a custom element that you use inside of the iron-list
<dom-module id="my-item">
<template>
<div class="item">
...
<a href$="{{_getProject(item.project_id)}}">...</a>
</div>
</template>
<script>
Polymer({
is: 'my-item',
properties: {
item: Object
},
_getProject: function(url) {
return 'webservices/api/projects/' + url
}
});
</script>
</dom-module>
<iron-list items="[[data]]" as="item">
<template>
<my-item item="[[item]]"></my-item>
</template>
</iron-list>
Define the _getProject function on your main template
<template is="dom-bind" id="app">
...
<iron-list items="[[data]]" as="item">
<template>
<div>
<div class="item">
...
<a href$="{{_getProject(item.project_id)}}">...</a>
</div>
</div>
</template>
</iron-list>
</template>
<script>
var app = document.getElementById('app');
app._getProject = function (url) {
return 'webservices/api/projects/' + url
}
</script>
I have a Polymer web app which I've generated with Yeoman. The below fragment shows how pages are defined in the index.html:
<iron-pages attr-for-selected="data-route" selected="{{route}}">
<section data-route="home">
<paper-material elevation="1">
<my-greeting></my-greeting>
</paper-material>
</section>
<section data-route="users">
<paper-material elevation="1">
<h2 class="paper-font-display2">Users</h2>
<p>This is the users section</p>
Rob
</paper-material>
</section>
So basically you define a section for each page.
Is it possible to define these sections as references to some external files? I would not want to add everything in the main index.html as it will get messy pretty soon.
It is possible but not in HTML unless you use ajax/ iFrames(No) to load the content and that would get ugly and would stop crawlers from properly crawling all your pages.
You would need to convert your pages to Java, Python, PHP, .net frameworks.
Since you sound new to this, I would just advise you to use WordPress.
There are many template there and it is easy to create and customise in the future.
Typically client side routing is used in single page applications, where the server-side code is primarily used to provide a RESTful API the client-side code uses via Ajax.
Then you would be look at using Angluar.js
Update:
Here's a cleaner version to do this:
<dom-module id="dyn-import">
<template>
<div id="container">
<link rel="import" href="{{href}}"/>
</div>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'dyn-import',
properties: {
href: {
type: String,
notify: true
}
},
attached: function() {
var container = this.$.container;
var link = Polymer.dom(container).querySelector('link[rel="import"]');
link.addEventListener('load', function() {
var importedDoc = link.import;
var importedNode = document.importNode(importedDoc.firstChild, true);
container.innerHTML = importedNode.innerHTML;
});
}
});
})();
The imported HTML can contain Polymer elements, that's working fine. The whole thing doesn't seem to be working on Safari. Also, I still seem to have some issues around relative URLS (say the imported HTML fragment references another Polymer element using HTML import - it does seem to work, but there's an error on the console and the URL in the error seems to have been constructed like this: web appreciation host + relative url which is clearly wrong).
I have finally solved this by writing a Polymer component (well, after all it's a Polymer application :)
<dom-module id="dyn-import">
<template>
<div id="{{id}}">
<link rel="import" href="{{href}}"/>
</div>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'dyn-import',
properties: {
href: {
type: String,
notify: true
},
id: {
type: String,
notify: true
}
},
ready: function() {
this.id = "ID_" + new Date().getTime();
},
attached: function() {
var sel = d3.select('#'+this.id);
var link = sel.select('link[rel="import"]');
link[0][0].addEventListener('load', function() {
var importedDoc = link[0][0].import;
var importedNode = document.importNode(importedDoc.firstChild, true);
sel.html(importedNode.innerHTML);
});
}
});
})();
</script>
This can then be used in the index.html as follows:
<section data-route="contact">
<paper-material elevation="1">
<dyn-import href="elements/contacts.html"></dyn-import>
</paper-material>
</section>
I have one further concern, is it a search engine friendly solution?
We have a custom element that is making an AJAX call to fetch some html generated on the server side and then injected into its light dom via Polymer.dom(this).innerHTML. The response coming from the server has another custom element in it that exposes a CSS property for theming purposes. On the main page, we're setting the value for the property, but it doesn't appear to be working. How do we get Polymer to style dynamically added light DOM elements that are distributed by another element.
index.html
<style is="custom-style">
x-bar {
--mixin-property: {
background: red;
};
}
</style>
...
<body>
<x-baz>
</x-baz>
</body>
x-baz.html
<dom-module id="x-baz">
<template>
<x-foo></x-foo>
</template>
</dom-module>
<script>
Polymer({
is: "x-baz"
});
</script>
x-foo.html
<dom-module id="x-foo">
<template>
<iron-ajax auto url="..." last-response="{{response}}"></iron-ajax>
<content></content>
</template>
</dom-module>
<script>
Polymer({
is: "x-foo",
properties: {
response: {
type: String,
obeserver: 'responseChanged'
}
},
responseChanged: function(newVal)
Polymer.dom(this).innerHTML = newVal;
}
});
</script>
x-bar.html
<dom-module id="x-bar">
<style>
.elementToStyle {
#apply(--mixin-property);
}
</style>
<template>
<div class="elementToStyle">
...
</div>
</template>
</dom-module>
</script>
Polymer({
is: "x-bar"
});
</script>
The iron-ajax call returns <x-bar> ... </x-bar>.
I would expect the div inside the x-bar that comes back from the AJAX response to have a red background, but it doesn't seem to be working. What do we need to adjust to make this work correctly?
Thanks in advance!