I am writing a simple widget that will create an output based on fetched data (taken from an AJAX request).
This version of the my-element
is the non-configurable, standard one:
http://jsbin.com/rivala/edit?html,output#H:L56
Thing is, I want the user to be able to decide what the output will look like. Since Polymer doesn't allow us to extend existing elements, I went the other way around: I create a behaviour (err... excuse me, a behavior
, it's so hard not to type that "u" every time) that does most of the work. Here is my result:
http://jsbin.com/yuxecu/edit?html,output
So, in order to create create an element, all the user needs to do is:
<dom-module id="my-element">
<template>
<!-- THE FOLLOWING PART IS THE ONLY THING THE USER WILL CHANGE -->
<paper-dropdown-menu label="Your favourite category">
<paper-menu class="dropdown-content">
<template is="dom-repeat" items="{{_data}}">
<paper-item>{{item.name}}</paper-item>
</template>
</paper-dropdown-menu>
</template>
<script>
Polymer({
is: "my-element",
behaviors: [ MyBehaviour],
})
</script>
</dom-module>
And then use it:
I would have much much preferred something a little easier. For example, it would have been much nicer to allow something like this:
<my-element url="http://output.jsbin.com/zonona/3.js">
<template id="bindme">
<!-- THE FOLLOWING PART IS THE ONLY THING THE USER WILL CHANGE -->
<paper-dropdown-menu label="Your favourite category">
<paper-menu class="dropdown-content">
<template is="dom-repeat" items="{{_data}}">
<paper-item>{{item.name}}</paper-item>
</template>
</paper-dropdown-menu>
</template>
</my-element>
But I tried and tried and then tried some more, and it doesn't seem to be possible unless you really want to get your hands dirty.
Once extending non-native elements is possible, I assume I can just create an element declaratively that extends my-element
and defines a new template. Till then...
Questions:
Does my code seem to be following at least roughly Polymer's best practices?
Is there a much easier way to do this, that I didn't think of?
Any more comments?
Thank you as ever...
I don't know what I am doing is quite the same thing, but you might be able to draw inspiration from it. I have created a generic dialog box that will provide the results from a database query in it, with the headings data driven and the row size and content also data driven. I actually create this element dynamically in a "manager" element.
Something like this is how the manager retrieves the data and creates the dialog (I call it a report-grid)...
newGrid: function(name, useId, useDates, parent) {
var self = this;
var body;
// jshint unused: false
var dataPromise = new Promise(function(accept, reject) {
var sendOptions = {
url: '/api/queries',
method: 'POST',
handleAs: 'json',
headers: {'content-type': 'application/json'}
};
body = {};
body.name = name;
if (useId) {
body.id = parent.id;
}
if (useDates) {
body.startdate = parent.startdate;
body.enddate = parent.enddate;
}
sendOptions.body = body;
var request = document.createElement('iron-request');
request.send(sendOptions).then(function() {
accept(request.response);
});
});
// jshint unused: true
var x;
var y;
var grid = document.createElement('pas-report-grid');
Polymer.dom(self).appendChild(grid);
if (this.grids.length === 0) {
x = 0;
y = 0;
} else {
x = this.grids[this.grids.length - 1].x + this.deltaX;
y = this.grids[this.grids.length - 1].y + this.deltaY;
}
this.grids.push(grid);
grid.open(dataPromise,body,x,y);
And then the element itself has a load of stuff (not shown) to provide drag and resize handles, but the core of the grid is the following templated stuff
<div class="layout horizontal">
<template is="dom-repeat" items="[[heading]]">
<span class="flex">[[item]]</span>
</template>
</div>
<iron-list id="grid" class="flex" items="[[data]]" as="row">
<template>
<div class="layout horizontal row" tabindex$="[[tabIndex]]" index="[[index]]">
<template is="dom-repeat" items="[[row]]" as="field">
<div class="flex field">[[field]]</div>
</template>
</div>
</template>
</iron-list>
The open function of the grid does this with the data
open: function(dataPromise, params, x, y) {
var self = this;
this.x = x;
this.y = y;
dataPromise.then(function(data) {
self.title = data.name;
self.heading = data.heading;
self.data = data.data;
self.$.griddialog.open();
});
this.params = params;
So what is happening here is the manager is making an iron request (also created dynamically) for a generic query that might or might not need an id and start and end dates, the server responds with a json object which contains a heading array, with a list of heading names, and a data array which is the rows, each row also being an array with the values from the query. I pass that info to the grid element as a promise - so it can get started, attach and so on, and then when the data arrives its loaded into a heading div and an iron list.
The grid element knows nothing about the actual query, how many fields each row will have, or indeed how many rows.