The GridPanel/Store saving description

  1. #1

    The GridPanel/Store saving description

    Hi All,

    I want to clarify the GridPanel/Store saving model:

    The content of GridPanel can be saved using to approaches:

    1. Using UpdateProxy
    2. Using ajax request to the page which contains Store control.

    If UpdateProxy is missing in Store then will be used second approach. For triggering saving need to call save function of GridPanel, for example

             <ext:Button runat="server" ID="btnSave" Text="Save" AutoPostBack="false" Icon="Disk">
                     <Listeners>
                            <Click Handler="#{GridPanel1}.save();" />
                     </Listeners>
              </ext:Button>
    I splitted description on several post for easy navigation

    ------------------
    1. Saving using UpdateProxy.

    If Store contain UpdateProxy then saving function will be pass saved data to update proxy. Examples of UpdateProxy

    Example1
                <UpdateProxy>
                    <ext:HttpWriteProxy Method="POST" Url="../Shared/Save.ashx" />
                </UpdateProxy>
    In this example the changed records will be submit to HttpHandler Save.ashx (instead handler you can use any aspx page)

    Example2
                 <UpdateProxy>
                    <ext:HttpWriteProxy Method="POST" Url="../Shared/CustomerService.asmx/SaveCustomers"           HandleSaveResponseAsXml="true" />
                </UpdateProxy>
    In this example we use WebService. Please pay attention that must be set two properties: Method=POST and HandleSaveResponseAsXml="true" (this indicate that save response from server will be has xml representation)

    How to handle submitted data on server

    The changed data submitted on server in "data" form field. You can retrieve with next code
        Request.Form["data]
    If you use webservice then signature of saving method should be (of course the name can be free)
            [WebMethod]
            public AjaxResponse SaveCustomers(string data)
            {
              .....
            }
    For easy handling of submitted data on server you can use StoreDataHandler class. The constructor of this class accept the HttpContext or submitted data (as string).
    This class allowing the developer represent the submitted data as Json string, as Xml or as Object collection (if you have bussines object on which can be mapped submitted data)
        StoreDataHandler dataHandler = new StoreDataHandler(context); // where context is HttpContext
        
        string json = dataHandler.JsonData;
        ChangeRecords<Customer> data = dataHandler.ObjectData<Customer>(); //as object collection
        XmlDocument xml = dataHandler.XmlData;
    The Object data return ChangeRecords<T> class. This class contains three collection
    List<T> Inserted
    List<T> Deleted
    List<T> Updated

    The developer can specified additional parameters which will be passed to server during save ajax request. The parameters can be specified in WriteBaseParams. In HtppHandler (or any page) these parameters can be retrieved from Request.Form collection, if using web service then each parameter must be in signature of web method

    Let's see on example of saving data in HttpHandler
            public void ProcessRequest(HttpContext context)
            {
                //Create instance and passing to the constructor HttpContext for automatically retrieving submitted data
                StoreDataHandler gd = new StoreDataHandler(context);
                
                //Class for building save response for confirmation on client
                AjaxResponse sr = new AjaxResponse(true);
    
                try
                {
                    //Convert data to business objects collection
                    ChangeRecords<Customer> data = gd.ObjectData<Customer>();
                    
                    //performs update actions
                    
                    foreach (Customer customer in data.Deleted)
                    {
                        Customers.Delete(customer);
                    }
    
                    foreach (Customer customer in data.Updated)
                    {
                        Customers.Update(customer);
                    }
    
                    foreach (Customer customer in data.Created)
                    {
                        Customers.Insert(customer);
                    }
                }
                catch (Exception e)
                {
                    //if were errors then we should to tell client that saving request was unsuccessful
                    sr.Success = false;
                    sr.Msg = e.Message;
                }
                
                //Convert AjaxResponse to json string and send to client
                sr.MakeAnswer();
            }
    Example with saving in WebService (please pay attention that for UpdateProxy should be set Method=POST and HandleSaveResponseAsXml="true"). The signature of web method can be siffer if using WriteBaseParams (in this case each parameter must be in signature)
            [WebMethod]
            public AjaxResponse SaveCustomers(string data)
            {
                //Create instance and passing to the constructor the submitted data
                StoreDataHandler gd = new StoreDataHandler(data);
                
                ... the same as in above example
    
                //return answer
                return sr;
            }

    2. Saving with internal Store saving model

    With this approach all form controls will be submit to server (as in classic postback)

    When the UpdateProxy is not specified then will be used internal Store saving. If was specified any IDataSource(SqlDataSource, ObjectDataSource and etc) then they will be used (will be called Insert, Delete, Update of IDataSource). The IDataSource can be specified in DataSourceID of Store

    The Store events sequence:
    - BeforeAjaxPostBack - fired before any store ajax action: now supported "update" and "refresh" actions. Available next properties in BeforeAjaxPostBackEventArgs: Action, Data (StoreDataHandler which contains submitted data), Parameters (parameters collection passed from client)

    if action == "refresh" then
    - RefreshData - fired when the should be refresh data. The developer should bind new data on this event. In StoreRefreshDataEventArgs available next properies: Parameters (parameters from client), Start, Limit, Sort, Dir (for suppoerting remote paging and sorting)

    if action == "update" then
    -- BeforeStoreChanged - fired before all actions related with modifications.In the BeforeStoreChangedEventArgs available: Parameters (parameters from client), DataHandler (StoreDataHandler which contains submitted data). In this event the developer can implenet own logic batch saving (using data from DataHandler). The Developer can set Cancel property of BeforeStoreChangedEventArgs to true for cancel all automatic modification actions

    if Cancel from BeforeStoreChangedEventArgs then perform next actions
    --- BeforeRecordUpdated - fired for each changed record before updating. If using IDataSource specified in DataSourceID then will be used Update function of IDataSource after this event. If doesn't specified then in this event the developer can specify own logic of updating. In BeforeRecordUpdatedEventArgs available: Record (XmlNode with changed record), keys (id field of changed record), NewValues collection, OldValues (now always empty, in future will be contain old values).
    The developer can cancel IDataSource action (set Cancel) or all Update actions (set CancelAll)
    --- AfterRecordUpdated - fired after IDataSource update calling (or after BeforeRecordUpdated if IDataSource doesn't specified)

    --- BeforeRecordDeleted
    --- AfterRecordDeleted

    --- BeforeRecordInserted
    --- AfterRecordInserted


    -- AfterStoreChanged - fired after all modification actions.

    - AfterAjaxPostBack - fired after all actions before building response for client. The developer can change AjaxResponse object in AfterAjaxPostBackEventArgs

    3. Saving with confirmation

    By default the Store on client need only Succes field for confirmation all changes. But there are cases when such behaivor is not applicable (for example, when part of records are saved successfully and part not, or when need to pass new id's to client for inserted records)
    For use confirmation need to set UseIdConfirmation="true" for Store. The Store has property RefreshAfterSaving (None, Auto, Always). The auto is default. The RefreshAfterSaving property manages refreshing behaivor after saving: None - no refreshing, Always - always refresh after saving, Auto - refresh if exists deleted or insterted records only. If using UseIdConfirmation="true" then RefreshAfterSaving can set to None.
    If developer using confirmation then he must build confirmation list for returning to client.

    Example if using UpdateProxy (HttpHandlers, aspx pages, web services and etc)
            public void ProcessRequest(HttpContext context)
            {
                StoreDataHandler gd = new StoreDataHandler(context);
                AjaxResponse sr = new AjaxResponse(true);
                
                //build initial confirmation list and passing to constructor id field name
                ConfirmationList confirmationList = gd.BuildConfirmationList("CustomerId");
    
                try
                {
                    ChangeRecords<Customer> data = gd.ObjectData<Customer>();
                    foreach (Customer customer in data.Deleted)
                    {
                        Customers.Delete(customer);
                        
                        //Confirm action for current record
                        confirmationList[customer.CustomerId].ConfirmRecord();
                    }
    
                    foreach (Customer customer in data.Updated)
                    {
                        Customers.Update(customer);
                        
                        //Confirm action for current record
                        confirmationList[customer.CustomerId].ConfirmRecord();
                    }
    
                    foreach (Customer customer in data.Created)
                    {
                        Customers.Insert(customer);
                       
                        confirmationList[customer.CustomerId].ConfirmRecord();
                       
                        //DON'T FORGET TO PASS NEW ID WHEN CONFIRMING INSERTED RECORD
                        //if Id set on sql server side then need set new id when confirming record
                        //confirmationList[customer.CustomerId].ConfirmRecord(newId);
                    }
                }
                catch (Exception e)
                {
                    sr.Success = false;
                    sr.Msg = e.Message;
                }
    
                StoreResponseData response = new StoreResponseData();
                response.Confirmation = confirmationList;
                
                sr.Data = response.ToString();
                sr.MakeAnswer();
            }
    If using internal Store saving model the need confirm records in AfterRecord... events. If IDataSource exist then records will be confirm automatically (based on recordAffected argiment in IDataSource callback function but ned id must be setted by the developer manually). If no IDataSource then developer must confirm all actions

            private string insertedValue;
            protected void SqlDataSource1_Inserted(object sender, SqlDataSourceStatusEventArgs e)
            {
                //use e.AffectedRows for ensure success action. The store read this value and set predefined Confirm depend on e.AffectedRows
                //The Confirm can be granted or denied in OnAfterRecord.... event
                //e.Command.Parameters["@SupplierID"] - output parameter of SqlDataSource
                insertedValue = e.Command.Parameters["@SupplierID"].Value != null
                                    ? e.Command.Parameters["@SupplierID"].Value.ToString()
                                    : "";
            }
            
            protected void Store1_AfterRecordInserted(object sender, AfterRecordUpdatedEventArgs e)
            {
                //If IDataSource specified then deleted and updated records confirms automatic (depending AffectedRows field)
                //But you can override this in AfterRecordUpdated and AfterRecordDeleted event
                //For insert we should set new id for refresh on client
                //If we don't set new id then old id will be used            
                if(e.Confirmation.Confirm &amp;&amp; !string.IsNullOrEmpty(insertedValueId))
                {
                    e.Confirmation.ConfirmRecord(insertedValueId);
                    insertedValue = "";
                }
            }
    Please don't hesitate to post your questions
  2. #2

    RE: The GridPanel/Store saving description

    Awesome vlad, thanks for the breakdown.

    Cheers,
    Timothy
  3. #3

    RE: The GridPanel/Store saving description

    Hi Vlad I have a question where does the Customer come from I working on a simple Update / Delete /Insert but I just don't understand how the UpdateProxy works if you can please send me an sample I't would help me allot.


    Thanks
  4. #4

    RE: The GridPanel/Store saving description

    In case that can help you, have some good examples in the example explorer (especially GridPanel / Service Connections / Handler using) that show this kind of stuff.
    U can also see Grid Panel / Misc / Details window.
    Gl.
  5. #5

    RE: The GridPanel/Store saving description

    EDIT: This post has been moved to*http://forums.ext.net/showthread.php...4664-16-1.aspx


    *Hi Vlad,

    hope you can help me, I can't get rid of saving more then one record chenged.

    I read your description above but my code does not work.

    I'm able to save only the first record changed.

    This is my structure: XpoDataSource -> Store -> GridPanel.
    I can succesfully fetch data, I use AfterRecordUpdated ajax event to save data.
    I understood that code executes so many times the number of records are changed, but event code executes only once.

    DataSource:

    
    <dxxpo:XpoDataSource ID="XpoDataSourceTemplateMail" TypeName="it.methode.pareto.ParetoLib.crm.mailing.TemplateMail"
    ******* runat="server">
    *** </dxxpo:XpoDataSource>
    Store:

    
    <ext:Store ID="StoreTemplateMail" DataSourceID="XpoDataSourceTemplateMail" runat="server"
    ******** OnRefreshData="StoreTemplateMail_RefreshData"
    ******** OnAfterRecordUpdated="StoreTemplateMail_RecordUpdated"
    ******** OnAfterRecordDeleted="StoreTemplateMail_RecordDeleted"
    ******** RefreshAfterSaving="Always" OnAfterAjaxEvent="StoreTemplateMail_AjaxPostBackResult">
    ******* <Reader>
    *********** <ext:JsonReader ReaderID="Oid">
    *************** <Fields>
    ******************* <ext:RecordField Name="Oid" />
    ******************* <ext:RecordField Name="TipoTemplateID" />
    ******************* <ext:RecordField Name="Descrizione" />
    *************** </Fields>
    *********** </ext:JsonReader>
    ******* </Reader>
    ******* <Listeners>
    *********** <LoadException Handler="Ext.Msg.alert('TEMPLATE MAIL - LOAD FAILED', e.message || e );" />
    *********** <CommitFailed Handler="Ext.Msg.alert('TEMPLATE MAIL - ERRORE', msg);" />
    ******* </Listeners> 
    *** </ext:Store>
    AjaxEvent:

    
    // this executes ONLY once, even if I changed more than one record
    protected void StoreTemplateMail_RecordUpdated(object sender, AfterRecordUpdatedEventArgs e)
    ******* {
    *********** int _id = int.Parse(e.Keys["Oid"].ToString());
    *********** int _tipoTemplateID = int.Parse(e.NewValues["TipoTemplateID"].ToString());
    
    *********** MyLib.crm.mailing.TemplateMail _tm = this.PersistentSession.GetObjectByKey<MyLib.crm.mailing.TemplateMail>(_id, true);
    
    *********** if (_tm != null)
    *********** {
    *************** _tm.Descrizione = e.NewValues["Descrizione"].ToString();
    
    *************** if (_tipoTemplateID != -1)
    ******************* _tm.TipoTemplate = this.PersistentSession.GetObjectByKey<MyLib.crm.mailing.TipoTemplate>(_tipoTemplateID, true);
    
    *************** _tm.Save();
    *********** }
    ******* }
    I also tried this:

    
    protected void StoreTemplateMail_BeforeStoreChanged(object sender, BeforeStoreChangedEventArgs e)
    ******* {
    *********** List<MyLib.crm.mailing.TemplateMail> _records = (List<MyLib.crm.mailing.TemplateMail>)e.DataHandler.ObjectData<MyLib.crm.mailing.TemplateMail>().Updated;
    
    ******* }
    But code above (StoreTemplateMail_BeforeStoreChanged) gives me a TargetInvocationException!

    I hope is clear, let me know.
    Please, add some annotation for "Inserting" if there is something different compared to update model.
    Thanx a lot

    Matteo
  6. #6

    RE: The GridPanel/Store saving description

    Hi Matteo,

    It would be best to start a new thread with your post.*


    Post a link cross referencing the threads if they're releated.*


    Geoffrey McGill
    Founder
  7. #7

    RE: The GridPanel/Store saving description

    *yesss, immediately


    EDIT: See related POST at*http://forums.ext.net/showthread.php...4664-16-1.aspx
  8. #8

    RE: The GridPanel/Store saving description

    why i can't fire the event BeforeRecordInserted or else. I write as follow:

    ext:Store ID="Store1" runat="server" OnBeforeRecordInserted="Store1_BeforeRecordInserted" OnBeforeRecordUpdated="Store1_BeforeRecordUpdated">
    and the.cs code as follow:
     protected void Store1_BeforeRecordInserted(object sender, BeforeRecordInsertedEventArgs e)
            {
                string s = e.Record.ToString();// here is a breakpoint
            }
  9. #9

    Cannot see refreshaftersaving property at store

    I use version 2. Is this the reason? Is there any replacement property.

    I want to update grid because i use entity field's onchanging events

    Thanks
  10. #10

    The GridPanel/Store saving description using Razor Engine

    Hi ,
    Can you give us an Example of this nice descroption Using Razor Engine .

    Just a Simple Description Becuse in Razor Engine I did not find the propretie "UpdateProxy"

    Thinks.

Similar Threads

  1. Replies: 2
    Last Post: Apr 14, 2011, 9:03 AM
  2. Pop-up error message when saving store!
    By xmdxxa in forum 1.x Help
    Replies: 1
    Last Post: Mar 31, 2011, 6:36 AM
  3. using DataTable as Store and saving data
    By angel colmenares in forum 1.x Help
    Replies: 0
    Last Post: Apr 16, 2010, 12:13 AM
  4. [CLOSED] Error 500 saving grid store
    By harafeh in forum 1.x Legacy Premium Help
    Replies: 4
    Last Post: Jun 30, 2009, 2:59 PM
  5. [CLOSED] GridPanel store saving
    By methode in forum 1.x Legacy Premium Help
    Replies: 11
    Last Post: Dec 16, 2008, 3:02 AM

Tags for this Thread

Posting Permissions