polymerfire
polymerfire copied to clipboard
Need to manually / force notify change to dom-repeat when firebase query data are not directly exposed
Description
I don't know if I'm doing it wrong or if it's really an issue (polymerfire ? polymer ?).
In my app, I have to display some parts of a Firebase query results (I don't have implemented Elasticsearch yet). For that, I do not directly expose the query data in order to be able to "filter" them. I populate "filtered" data with "raw" data which interests me.
All seems to be ok, except when I update values in the Firebase console. dom-repeat does not receive change notifications, however "raw" and "filtered" data are ok and well reflect what is stored in the database.
The only workaround I've found is to manually/force notify change on "filtered" data with something like:
this.set(path, this.get(path));
Code exemple (sorry no live demo)
<!-- Polymer elements -->
<link rel="import" href="../bower_components/polymer/polymer.html">
<!-- Firebase elements -->
<link rel="import" href="../bower_components/polymerfire/firebase-app.html">
<link rel="import" href="../bower_components/polymerfire/firebase-query.html">
<dom-module id="gbx-test">
<template>
<firebase-app api-key="YOUR_FIREBASE_API_KEY" auth-domain="YOUR_FIREBASE_AUTH_DOMAIN" database-url="YOUR_FIREBASE_DATABASE_URL" name="test" app="{{firebaseApp}}"></firebase-app>
<firebase-query data="{{_data}}" app="{{firebaseApp}}" path="/data" app-name="test"></firebase-query>
<template is="dom-repeat" items="{{_computedData}}">
<div>
{{item.name}}
</div>
</template>
</template>
<script>
Polymer({
is: "gbx-test",
properties: {
_data: {
type: Array
},
_computedData: {
type: Array,
value: function(){
return [];
},
notify: true
}
},
observers: [
"_onDataItemsChanged(_data.splices)",
"_onDataItemsChanged2(_data.*)"
],
_onDataItemsChanged: function(changeRecord){
if(changeRecord){
// for the example we don't filter anything
this._computedData = changeRecord.indexSplices[0].object;
}
},
// here is the workaround
_onDataItemsChanged2: function(changeRecord){
if(changeRecord.path.split(".").length > 2){
var path = changeRecord.path.replace("_data", "_computedData");
this.set(path, this.get(path));
// or
// this.set(changeRecord.path.replace("_data", "_computedData"), changeRecord.value);
}
}
});
</script>
</dom-module>
Steps to reproduce
- Create a test database in your Firebase console
- Import the test data test-data.json.txt
- Create a component with the above code example
- Replace
YOUR_FIREBASE...
with those of your Firebase test database - Play
Browsers Affected
- [x] Chrome
- [x] Firefox
- [ ] ... and probably all others
Additional notes
Content of test-data.json.txt
{
"data" : [ null, {
"name" : "original data 1"
}, {
"name" : "original data 2"
} ]
}
I (think?) this is expected behavior for a dom-repeat
with a filter, at least I've run into this both with Firebase and non-Firebase apps. @cdata @robdodson is it expected that the render will have to be manually triggered?
I can't remember the change record api off the top of my head unfortunately. Polymer's data binding system works by object reference, so if any of the object references are the same after your change, it won't trigger the bindings to run. (BTW we're fixing this soon). Calling this.set
should poke the data binding system to tell it to look at the new objects so your workaround may be the correct solution if there's the possibility that the object references remain the same but their inner contents have changed