Reputation: 696
Let me start with I have a solution, but I don't really think it is elegant. So, I am looking for a cleaner way to do this.
I have an EntityProxy displayed in a view panel. The view panel is a RequestFactoryEditorDriver only using display mode. The user clicks on a data element and opens a popup editor to edit a data element of the EntityProxy with a few more bits of data than is displayed in the view panel. When the user saves the element I need the view panel to update the display.
I ran into a problem because the RequestFactoryEditorDriver of the popup editor flow doesn't let you get to the edited data. The driver uses the same passed in context that you use to send data the server, Yet the context returned out of flush only allows a Receiver<Void>
even if you cast it to the type of context you stored in the editor driver in the edit() call. [It doesn't appear to send and EntityProxyChanged event either, so I couldn't listen for that and update the display view. - scratch this - I see now this event is not for this use case]
The solution I found was to change my domain object persist to return the newly saved entity. Then create the popup editor like this
editor.getSaveButtonClickHandler().addClickHandler(createSaveHandler(driver, editor));
// initialize the Driver and edit the given text.
driver.initialize(rf, editor);
PlayerProfileCtx ctx = rf.playerProfile();
ctx.persist().using(playerProfile).with(driver.getPaths())
.to(new Receiver<PlayerProfileProxy>(){
@Override
public void onSuccess(PlayerProfileProxy profile) {
editor.hide();
playerProfile = profile;
viewDriver.display(playerProfile);
}
});
driver.edit(playerProfile, ctx);
editor.centerAndShow();
Then in the save handler I just fire() the context I get from the flush(). While this approach works, it doesn't seem right. [It would seem I should subscribe to the entitychanged event in the display view and update the entity and the view from there. - once again scratch, same reason as before ] Also this approach saves the complete entity, not just the changed bits, which will increase bandwidth usage.
What I would think should happen, is when you flush the entity it should 'optimistically' update the rf managed version of the entity and fire the entity proxy changed event. Only reverting the entity if something went wrong in the save. The actual save should only send the changed bits. In this way there isn't a need to refetch the whole entity and send that complete data over the wire twice.
Is there a better solution?
Upvotes: 2
Views: 1858
Reputation: 696
I found a better solution. I make the proxy editable before calling the RequestFactoryEditorDriver edit() and save the editable proxy as my view proxy.
PlayerProfileCtx ctx = rf.playerProfile();
playerProfile = ctx.edit(playerProfile);
driver.edit(playerProfile, ctx);
Also, (and I thought I had tried this before and it didn't work but I must have done something wrong then) I can cast the context that comes back from the flush. It is the same context I sent to the driver with the edit()
call so it is safe.
PlayerProfileCtx ctx = (PlayerProfileCtx) driver.flush();
Doing this fixed the problem with rf sending the whole object with fire() and not just the diffs. I'm not sure why though. That might be a bug in the RF Editor Driver.
So now I have the data from the driver already in the view and don't have to depend on sending it back from the server. But I did register for EntityProxyChange events so I could detect and refetch if there was a conflict on the server.
Upvotes: 1
Reputation: 64541
You don't seem to really understand the details of what's going on with RF; plus, your terminology doesn't really help in understanding (flush vs. fire).
A proxy in RF is a snapshot of the server's state at the time you retrieved it. You can do whatever you want with the entity elsewhere in your app (through other proxies), your proxy won't ever change to reflect those modifications.
An EntityProxyChange
event is dispatched on the client-side (for an entity that is already known by the server and has been sent from the client) when the server has detected that it has changed: either its version (as returned by getVersion
on the Locator
) has changed, or it has been deleted (as told by the isLive
method of the Locator
). If you don't use a Locator
, it'll use the getVersion
of the entity and isLive
will be replaced by find
ing the entity by its ID (as returned by its getId
method) and checking for null
(this is also the default implementation of isLive
in the Locator
).
In your case, if you don't see an EntityProxyChange
being dispatched, then check that you correctly update the entity's version.
Finally, RF always sends a diff of your changes to the server (except for a ValueProxy
, in which case a diff would have no meaning). As for retrieving data, it doesn't retrieve linked proxies by default, unless you explicitly ask for them using with
; and this is independent of what you possibly sent about the entity.
In your case, to update the view panel, you have 3 possibilities:
EntityProxyChange
events or after an explicit signal from your popup; you could use the find
method of RequestContext
with the proxy's stableId
as argument, and the appropriate with
for the properties you need).EntityProxyChange
events too)save
method of your request context return the saved entity, or call the find
method in the same request context to batch the save
and find
together in the same HTTP request.All in all, I think I'd go with the current solution. Regarding your code though, I'd launch the popup with the proxy and a callback, and leave the request context and editing editor driver as implementation details of the popup: you only need that it calls the view panel back when it's done, passing the updated proxy as an argument to the callback.
A last word regarding terminology: you flush an editor driver to copy the field's value back to the object/proxy, and (independently, but in your case sequentially) you fire a request context to send a batch of service methods and proxy changes to the server. Flushing an editor driver doesn't send anything to the server, these are distinct actions.
Upvotes: 2