I am using anvil server to call out to an external service to retrieve some data. Two properties (createdAt, updatedAt) are stored in epoch time. I am trying to pass the result of this data to a component and convert the values to readable dates at run time, but it seems to not pick up the modifications to the properties before the component loads, and I am not sure how to cause the bindings to update. I tried using self.{childComponent}.refresh_data_bindings() to no effect.
Here is a code snippet where I try to convert the data:
class AccessProfileDetails (AccessProfileDetailsTemplate):
def __init__(self, **properties):
self.init_components(**properties)
self.env = 'QA'
# Any code you write here will run when the form opens.
self.item = anvil.server.call('getAccessProfile', self.env, self.profile_id)
self.item['createdAt'] = Utils.format_date_time(long(self.item['createdAt']))
self.item['updatedAt'] = Utils.format_date_time(long(self.item['updatedAt']))
self.created_at_display.refresh_data_bindings()
self.updated_at_display.refresh_data_bindings()
print(self.item['createdAt'])
print(self.item['updatedAt'])
The created_at_display and updated_at_display components still show the epoch time in the UI when I run the app. The print statements print the dates as expected.
I would try putting any code that ends in displaying something in the “show” event rather than in “init”. You can’t be sure any visual components are ready until then.
Actually, on rereading that … what is “created_at_display” ? If I assume it is a repeating panel or another form then it should handle the displaying of the item data just fine. Have you tried printing the values from within the target form to make sure “item” has passed correctly? If it has, have you bound the variables correctly to whatever is displaying them?
Happy to take a look if you want to post a clone link either here or in PM.
Data bindings are part of the form, not of the components themselves, so what you want to do is call self.refresh_data_bindings(). (In fact, that data-binding refresh is triggered implicitly by setting self.item, so you could also just set the 'createdAt' and 'updatedAt' keys of that dictionary before setting self.item.)
Here’s a forum post where I walk through the mechanics of data bindings, which should hopefully help you understand why this is happening (read from the heading “how data bindings work”):
(@david.wylie, I’m afraid you’re off base here. The only thing that isn’t valid until the show event is custom Javascript. Everything else can and should be handled in __init__.)
I think I’ve got it! I followed the live example posted in the link and I made some of my own modifications, and it now works exactly as I intended.
from anvil import *
import anvil.server
import tables
from tables import app_tables
import Utils
class StandardDisplayField (StandardDisplayFieldTemplate):
def __init__(self, **properties):
# You must call self.init_components() before doing anything else in this function
label_input = None
value_input = None
self.init_components(**properties)
# Any code you write here will run when the form opens.
@property
def label_input(self):
return self.label.text
@label_input.setter
def label_input(self, value):
self.label.text = value
@property
def value_input(self):
return self.value.text
@value_input.setter
def value_input(self, value):
if self.type_input == 'text':
self.value.text = value
elif self.type_input == 'epoch':
self.value.text = Utils.format_date_time(long(value))