I’ve got a simple configurations table in my Perspective application. It’s used to populate various dropdowns in other views. Multiple users can edit the table. It seems to me …
I don’t want a polling binding to the database as it’s wasteful.
I want to keep the user in the same pager page and on the same selected row. The binding refresh would have to respect that.
I should indicate to the user that the data has been changed and, perhaps, give the opportunity to refresh by button.
How do others manage this? Do I create a memory tag to log the last update time and bind the refresh button’s visibility to that?
Sounds like a job for message handlers.
When a client saves changes, a message is sent to all other clients informing them a change has taken place. Then you can either refresh the table automatically or prompt the user to manually refresh.
Here's the Edit Message Handler to set my table refresh button's visibility. It's on the button's Message Handlers configUpdate script.
def onMessageReceived(self, payload):
system.perspective.print('configUpdate message received')
if payload.has_key('table'):
if payload['table'] == 'config': # Corrected after code_skin's comment.
self.meta.visible = True
system.perspective.print('Refresh visible')
I have the Listen Scopes set to Session + Page + View in an attempt to get it to work. The message handler is not firing on update of the table cell.
Can anyone clarify what settings I require to sendMessage all active clients that the table has been update?
What scope should be specified in the sendMessage?
What scope should be specified in the message handler?
Update: When I print the msg variable I get the following which I suspect is one of our guys using the Vision client version of the application. I don't see any sign of me using the Perspective version.
You need to specify perspective scopes here; session, page, or view
String scope - The scope that the message should be delivered to. Valid values are "session", "page", or "view". If omitted, "page" will be used. [optional]
They seemed to use shorthand 'S', 'C' or 'G' (gateway) somewhere in the documentation. I've changed to 'session' and the returned value from sendMessage is
Am I right in thinking that I can send directly from one client to all the others? I don't need to send it to the gateway and have it broadcast it, do I?
You are confusing system.util.sendMessage with system.perspective.sendMessage. In this case, if all editing is done in Perspective, sending to Perspective’s session scope should be the right answer.
so it looks like it's seeing another client. The clients still aren't triggering. (I just have a system.perspective.print in the onMessageReceived for now. Listen Scopes is set to Session.)
Reading through the documentation again, I'm beginning to think that component message handlers can't see system.util.sendMessage messages but only system.perspective.sendMessage messages. Component message handlers says:
The idea being that some other component will broadcast a message, and if the type of the message matches what the Message Handler is listening for, the Message Handler will execute a script.
That means I am going about this the wrong way and that I need to:
Create a Project Browser | Session Events | Message | configUpdate session message handler to receive a broadcast message.
Have that create a system.perspective.sendMessage and pass the payload to the components in the session.
I can't get the session message handler to detect the incoming message though.
It's a little bit simpler than that.
system.perspective.sendMessage() takes a sessionID parameter that you can use to directly send messages to other sessions.
Try something like this:
def broadcastPerspectiveMessage(messageType, payload):
"""Broadcast a Perspective message to all sessions in the current project."""
project = system.util.getProjectName()
sessions = system.perspective.getSessionInfo(projectFilter=project)
scope = 'session'
for session in sessions:
try:
system.perspective.sendMessage(messageType, payload, scope=scope, sessionID=session['id'])
except:
# Try/except to avoid 'Unvalid UUID String' errors from open designer sessions.
pass
And on a message handler on your table (with message type of ConfigTableSaved listening to Session messages):
if payload['sessionID'] == self.session.props.id:
# Do something on the session that initiated the save.
pass
else:
# Do something on all other listening sessions.
pass
# Do something for all sessions.
pass
Thanks for this information. I haven’t found anything like this. All the documentation and examples suggest that I can just send a broadcast using system.util.sendMessage and the others will pick it up. Your approach seems to target them all individually.
Q1. Where does the broadcastPerspectiveMessage code go? Scriptiong | Project Library or on the gateway?
Q2. You seem to be bypassing the Session Event message handler and going directly to the component message handler. Can you do that?