PDA

View Full Version : How to save a store and form in sequence?



cgi-bin
24 Apr 2014, 7:18 AM
Using ExtJs 3.4.1.1

I have a complex page that is mostly a form. Saving that is simple and has been working well. However, the need has arisen for the need to associate a dynamic list of data (url links) with the main form data.

I implemented that using a store and dataview. It was a bit tricky to get working to display the way I wanted... it's not perfect but it works. I can dynamically add/remove/edit the entries of the dataview within the main form.

My issue is now saving both the store that holds the list and the main form in sequence.

store.save() only returns a "batch number" or -1 if there was nothing to save. I cant figure out how to best sequence everything to save the main form first, wait for success or fail, then if success, save the store.

A little more detail if it helps...

I have a formpanel. In the top toolbar of that panel I have a combobox (linked to storeA) and several buttons (new, edit, save, cancel). The user can use the "New" button to fill out the form from scratch, or choose an entry in the combobox which tells two stores to issue read requests for the details to populate the form. The main store (storeB) just gets one record and populates the form fields. The second store (storeC) contains the list of records that feeds the new dataview. By default the form is read-only, but if the user clicks the edit button, it enables the form to be edited and saved. I made my template for the dataview have edit and delete buttons for each item shown as well as a new button to add items. These buttons are only available when the main form is in "Edit Mode", otherwise the entries from storeC are shown as simple links.

That who process is working OK. Maybe not the ideal way to do it, and I'm open to suggestions for a better way. However my main issue is now the saving part. The Save button in the toolbar calls a function that checks to see if the form is valid, then calls form.submit(). With a success/fail handler. If the main form saved successfully, then I call the storeC.save(). I also reload storeA (the combobox) and re-select the original value to reload storeB to re-populate the form with the newly saved values. This also reloads storeC. Since storeC.save is non-blocking, all of this happens simultaneously and I have a race condition. As long as the storeC save worked, there really isn't an issue... it all seems to work. (actually I'm sometimes seeing an error in my log: "Uncaught TypeError: Cannot read property 'reMap' of null" line 25228 in ext-all-debug.js) But if storeC.save failed for some reason (back-end validation), then I loose the changes that were made because when the combobox value is set, it loads both storeB and storeC based on the value, and storeC loses the changed values.

This has become a convoluted mess... I've thought of a couple possible options, but I'm thinking there has to be a more elegant way to do this.

First problem, would be that storeA and storeB are basically reading the same data, but storeA only contains a sub-set of the fields, and storeB contains the details for one record of storeA. I know I could store all of the data that storeB gets in storeA, but that would end up being a lot of data, and it would get stale pretty quickly. Also the back-end process that gets the details is complex. I'm not too concerned about this. It works. But I'm always open to suggestions for improvement.

My main probelem is that storeC contains a list of values also associated with the value selected from storeA. (It is a list of hyperlinks (id/display/url fields), unknown length, so I cant just have dumb fields for link1-link10 or something.) I guess theoretically, I could have an array as one of the data values in storeB, but I've never really seen an easy way to deal with multi-dimensional store values... How would I set up the store fields to deal with that? How would I use it to feed the dataview (or some other way to display all the links when the form is in read-only mode, and add/edit/delete those values when in edit mode)? How would I write that back when saving the form? I've thought about adding a hidden field in the form and somehow serializing the data in storeC so that I only have to save the form and not worry about dealing with storeC.save. But how to do that with new/edited/deleted records (getModifiedRecords only gives new/changed but not deleted)? I guess I could just serialize the whole store and let the back-end handle figure out what has changed, but that seems like a kludge.

I could always try to save storeC first and then in the write handler (only called on success, correct?) submit the main form. I would have to check to see if the result from storeC.save is -1 and call the form submit right away since write wouldn't fire. However, this means that I couldn't create links when the form is creating a new record, because the parent wouldn't exist yet to relate the store data to on save. I'm mostly ok with limiting the ability to create/edit/delete the links to existing entries, but I'm sure end-users will complain.

I'm looking for advice and pointers to examples or suggestions on how to handle this complex mess.

Thank you.

cgi-bin
29 Apr 2014, 9:28 AM
I've basically figured this out. It might not be ideal, but it seems to work. I have a few tweaks to make with the template in the DataView and dealing with multiple potential messages/alerts, but that is a separate issue.

First I save storeC, however I have to keep track of what actions it needs to perform in order to know when it is fully done. So in the beforewrite handler I store the action in an object with a simple Boolean flag set to false. Then in the write handler I set it to true indicating it was successful. Finally, in the save handler, I check the object to see if all of the action types are true, and if so, then proceed to save the main form. I think I was initially expecting the write or save to automatically track if each of the actions were successfully completed or not, but I had to implement that myself.