ExtJS 4.1.0
Update 6/6/13:
I have posted this same question on the Sencha forums where there hasn't been much action. The post is more or less the same, but I figured I would add it here just for reference. I am still eager to hear other community members' input on what must be a very common scenario in an ExtJS Application! http://www.sencha.com/forum/showthread.php?265358-Complex-Model-Save-Decoupling-Data-and-Updating-Related-Stores
Update 7/16/13 (Conclusion?)
The Sencha post garnered very little discussion. I have decided to put the majority of the load of complex save operations on my application server and lazily refresh client stores where need be. This way I can use my own Database wrapper to encompass all of the transactions associated with one complex Domain Object save to guarantee atomicity. If saving a new Order
consists of saving the order metadata, ten new instances of OrderContents
and potentially other information (addresses residing in other tables, a new customer defined at the time of order creation, etc.) I would much rather send the payload to the application server, rather than establish a vulgar web of callbacks in client-side application code. Data which is associated on a One-to-One basis (such as an Order
hasOne Address
) is updated in the success
callback of the Order.save()
operation. More complex data, such as the Order
's contents, is lazily handled by simply calling contentStore.sync()
. I feel that this is the means to guarantee atomicity without an overwhelming number of client-callbacks
Original Post Content
Given the overall disappointing functionality of saving association-heavy models, I have all but ditched model associations in my application and rely retrieving associated data myself. This is all well and good, but unfortunately does not resolve the issue of actually saving the data and updating ExtJS stores to reflect the changes on the server.
Take for example saving an Order
object, which is composed of metadata as well as OrderContents
i.e., the parts on the order. The metadata ends up in an Order_Data
table in the database, whereas the contents all end up in an Order_Contents
table where each row is linked to the parent order via an order_id
column.
On the client, retrieving the contents for an order is quite easy to do without any need for associations: var contents = this.getContentsStore().query('order_id', 10).getRange()
. However, a major flaw is that this is hinging on the content records being available in the OrderContents
ExtJS Store, which would apply if I were using associations NOT returned by the data server with the "main" object.
When saving an order, I send a single request which holds the order's metadata (e.g., date, order number, supplier information, etc.) as well as an array of contents. These pieces of data are picked apart and saved to their appropriate tables. This makes enough sense to me and works well.
All is well until it comes to returning saved/updated records from the application server. Since the request is fired off by calling a OrderObject.save()
, there is nothing telling the OrderContents
store that new records are available. This would be handled automatically if I were to instead add records to the store and call .sync()
, but I feel this complicates the saving process and I would just much rather handle this decoupling on the application server not to mention, saving an entire request is quite nice as well.
Is there a better way to solve this? My current solution is as follows...
var orderContentsStore = this.getOrderContentsStore();
MyOrderObject.save({
success: function(rec, op){
// New Content Records need to be added to the contents store!
orderContentsStore.add(rec.get('contents')); // Array of OrderContent Records
orderContentsStore.commitChanges(); // This is very important
}
});
By calling commitChanges()
the records added to the store are considered to be clean (non-phantom, non-dirty) and thus are no longer returned by the store's getModifiedRecords()
method; rightly so as the records should not be passed to the application server in the event of a store.sync()
.
This approach just seems kinda sloppy/hacky to me but I haven't figured out a better solution...
Any input / thoughts are greatly appreciated!