iron-data-table
iron-data-table copied to clipboard
Two way binding with datasource
Hello,
So far I'm really impressed with iron-data-table, but I am wondering if you have tried two way binding when using a datasource instead of static items.
I am adding a path observer on the data I pass to the datasource callback, but I am getting no notifications that anything has changed.
I am testing with a simple paper-input element
Extracts from my code:
properties: {
data: {
notify: true,
value: function() {
return this._data.bind(this);
}
},
rows: {
type: Array,
notify: true
},
}
observers: [
'_dataChanged(rows.*)'
],
_data: function(opts, callback) {
this._dataCallback = callback;
// fetch set up here
this.$.request.execute();
},
_handleResponse: function(e, detail) {
this.rows = (detail.xhr.response && detail.xhr.response.rows) || [];
this._dataCallback(this.rows);
},
_dataChanged: function(cr) {
console.log(cr);
}
The column template is simply:
<template><paper-input value="{{item.remark}}"></paper-input></template>
But when I edit the column, _dataChanged isn't called.
I suspect it is because datasource is a function and not a two way binded object, could that be it? I have verified that it works when using items instead of datasource.
If not do you have an example of notifications with two-way binding when using a datasource?
Basically when the user edits a cell I just want a notification that the data has changed without having to add events to each paper-input or whatever elements are in the template.
Thanks and once again, a great piece of work!
ajy
Hi!
_dataChanged is not called since nothing is actually calling notifyPath('rows...') to notify the observers. When you bind rows directly to items it works, because then there is a binding by Polymer between these two properties.
When dataSource is used instead, rows is completely decoupled from the <iron-data-table> – this is by design since dataSource is meant for remote data.
What you in this case need, is to listen to an (undocumented unfortunately, I'll fix that) event called item-changed. That will be fired when an item is changed using two-way binding. It has three properties IIRC, item, which contains the item object, path which contains the changed property path, and value which contains the new value for that path.
(for some reason the event seems to be firing multiple times in some cases, I'll have a closer look on that)
Thanks, I will give item-changed a try.
An alternative could be to make datasource two way binding, a simple solution (I think) would be something like:
<remote-data datasource="{{datasource}}" options="[[options]]">
</remote-data>
<iron-data-table datasource="[[datasource]]" options="{{options}}">
</iron-data-table>
So remote-data would generate the data and this is passed out and into iron-data-table.
When the user filters, sorts or changes page then an options Object property in iron-data-table would be updated, this would be passed out and into remote-data which would observe changes to it's options property and generate new data.
This would then remove the need for datasource to be a function and also remove the need for the callback, which is not very Polymer.
What do you think?
ajy
Interesting idea, but I'm not entirely sure I understand how it would work with lazy loading – if options would change to request data for e.g. page 10/100, you would need to implement all kinds of paging logic inside <remote-data> so that it would push the new data in the correct place in dataSource (if I'm understanding correctly it's supposed to be an array?)
Also, when using a remote data source, <iron-data-table> needs to be told what is the total size of the dataset. Not sure how that would be handled in this case. I guess <remote-data> would need its own property for that.
Would the motivation to do this to workaround using a callback function or are there some other reasons?
The item-changed event worked a treat, thanks. But how do I update just one row of the table? In my situation the user can edit a cell or cells, the changed record is then sent to the server, the server saves the record to the database and returns the updated record. The updated record is not necessarily the same record as sent as it contains fields calculated by the server.
So I would like to update the changed row with the new record returned by the server? Is this possible? With items I guess I could just update the item, but with datasource?
How it's designed is that you should call clearCache() always when you want the data to be updated from server. But for updating just a single line, there's currently no functionality to do that.
@ajy2718 any luck? If you have more questions you can also reach me in the Gitter chat: https://gitter.im/Saulis/iron-data-table
Did you get to the bottom of why item-changed is firing more than once? I was similarly interested in responding to changes to table data, so implemented: listeners: { 'item-changed': '_handleChange' } with a simple _handleChange(event) function to log event.detail just to see the output for myself.
Using a paper-input element as the source cell, 'item-changed' seems to trigger twice for every character bearing keypress in the element. i.e. entering the "3" seems to result in 2 events being fired.
Also, is there any way to react to a change to an input cell only when focus is lost - at the moment 'item-change' seems to be fired for every key-click, i.e. entering the number 333 generates 6 events, two when the first digit is entered, 2 when the second digit is entered and the last 2 when the final digit is entered.
(Oh, I randomly tried using a simple element rather than a
Haven't had time to dig into the root cause unfortunately :'/
I think you just subscribe to listen for blur events on the inputs?
A regular <input> doesn't support two-way binding, you need to use atleast iron-input for that.
Hi Saulis,
No worries. Thanks for the tip regarding blur events - I'll look into that, perhaps the focusout event would work.... As regard elements, I did use an
As it happens, my particular use case involves a nested JSON structure, so I'll probably need to do a little more work anyway.