Here is my solution to make sure UI is updated if there is a data change in another browser.
Launching the form subscribes to a Firebase realtime database where I store last_updated value for each field identified.
Any time the client writes to Anvil, Firebase date is also updated.
Any time firebase last update date is updated, a redownload of data from anvil is triggered (instead of doing it based on a timer).
Limitations: 100 active fields can be tracked total in the free tier. That’s for all fields and for all users.
That is not much, but you can optimize this by using one tracker for all fields or pay a small amount to get 200k simultaneous connections.
If that is ok for you, here is how without going full firebase add-on route:
- Sign up for firebase, create a project, specify it as a web app, create a realtime db.
- In Anvil create a module called firebase_ and paste with your config version of the code:
import anvil.js
firebaseConfig = {
'apiKey': "AIzaSyChQb000000000000DrRN-CS1AgY5mk",
'authDomain': "testtest.firebaseapp.com",
'projectId': "testtest",
'storageBucket': "testtest.appspot.com",
'messagingSenderId': "7500000000245",
'appId': "1:75273000005:web:b61ca000001cea0000004ba4"
}
firebasejs = anvil.js.import_from('https://www.gstatic.com/firebasejs/10.7.2/firebase-app.js')
initializeApp = firebasejs.initializeApp
firebasedb = anvil.js.import_from('https://www.gstatic.com/firebasejs/10.7.2/firebase-database.js')
getDatabase = firebasedb.getDatabase
onValue = firebasedb.onValue
update = firebasedb.update
ref = firebasedb.ref
app = initializeApp(firebaseConfig)
db = getDatabase(app)
you don’t have to use data bindings, but here is anexample using them:
3) in a form with a field you want to keep updated:
class test_databind(test_databindTemplate):
def __init__(self, **properties):
self.init_components(**properties)
self.rowid = "1" #can be set through a property if you make this a reusable component.
starCountRef = firebase_.ref(firebase_.db, 'tmp/a'+str(self.rowid))
firebase_.onValue(starCountRef, self.update_value)
def update_value(self, snapshot, three):
if str(snapshot.val()) != self.latest_update:
self.item = app_tables.databind_test_table.search(id=self.rowid_value)[0] #.get didn't work
self.latest_update = str(snapshot.val())
def form_refreshing_data_bindings(self, **event_args):
self.latest_update = str(datetime.now())
firebase_.update(firebase_.ref(firebase_.db, 'tmp'), {"a"+str(self.rowid): self.latest_update})
This code sets up a writer that triggers to write to Firebase when data bindings are refreshed (in this case a two way binding that updates the DB as well).
It also sets up a listener onValue to call to get data from Anvil.
Security:
The firebase database has to be open and someone talented could overwrite the data or abuse the firebase db. No content data is shared with firebase, just the update date which is less sensitive.
Here is a gif of it working when set to trigger on Enter and Lost_focus for the textbox and using data binds that write to Anvil on the same event.
Future plans:
You can make it live (with a small delay) if you don’t use data bindings, instead read, write and update directly from code.