PDA

View Full Version : [CLOSED] MVC Grid Batch Editing



adelaney
Sep 24, 2012, 10:50 AM
I have a grid in an MVC application where I want to perform batch updates on a button click. The grid has the cell editing plugin in place. I have set up the button to connect to a DirectMethod, but I don't know how to pass any "bulk" parameters. In the example here: http://examples2.ext.net/#/GridPanel/Update/Batch/ the event sends back the sender and the event args, but I don't think that is really relevant to MVC. However, if it is, I don't know to configure the Params object of the button to provide those values. Can you please point me in the right direction?

Thanks in advance.

Daniil
Sep 24, 2012, 12:49 PM
Hi @adelaney,

You should pass this

#{Store1}.getChangedData({skipIdForNewRecords : false})
as a parameter of a DirectMethod request.

Configure the controller action with

string data
parameter and use this parameter directly instead of e.ExtraParams["data"].


ChangeRecords<TestPerson> persons = new StoreDataHandler(data).BatchObjectData<TestPerson>();

adelaney
Sep 24, 2012, 3:33 PM
I am so sorry. I forgot to mention that this is a treeGrid and not a "normal" grid. I tried the solution above, but it errored on "parameter mismatch." I have to assume that a TreeGrid does support this "changed data" in this way. :(

Daniil
Sep 24, 2012, 7:41 PM
Yes, TreeStore doesn't support the getChangedData method. We will consider a possibility to get it working.

adelaney
Sep 24, 2012, 8:00 PM
Um. Ok. However, I am not asking you to implement new functionality. You can if you would like. That seems nice, considering it is a grid. However, what I am asking is HOW, using your UI tool, do I solve this need. Are you telling me that there is no way to batch edit a TreeGrid? Am I not able to simply pass the entire Tree data and check a "dirty" property or something? If there is no way to batch edit, is there a way to mimick it via some client calls (i.e. looping through the tree and calling a single edit for every line)?

Daniil
Sep 24, 2012, 8:13 PM
Yes, you are right, iterating the nodes and using its isDirty and getChanges methods can help to get a changed data.

adelaney
Sep 24, 2012, 9:05 PM
Great! I can do that. So, back to the original question. How do I set up my view to send my data back to the controller? I tried this:

.Buttons(Html.X.Button.Text("Save Changes").Icon(Icon.Accept).Handler("#{DirectMethods}.SaveChanges()") _
.Params(Sub(params)
params.Add("#{storeReinsurerTree}.root.data")
End Sub
)) _

But that throws an error of "parameter count mismatch."

Daniil
Sep 25, 2012, 7:15 AM
Please use the Ext.net.DirectMethod.request method. Here is an example.
http://examples2.ext.net/#/Events/DirectMethods/WebService/

adelaney
Sep 25, 2012, 7:45 PM
An unfortunate issue I did not see coming would be some trouble with the length of JSON rendered from the tree. As a result, I have been trying a few things. One thing that seems to have some potential is using the Proxy to update and sync the store. I have been able to get the data to post to the controller and only the changed rows are posting - that's really helpful. However, there is one oddity: no date values are making it to the controller. They are all showing "null" ("#12:00:00 AM#"), but all the other data is mapping correctly. Is there something specific I need to configure on the TreeGrid model or ColumnModel columns in order to get the date fields to map through?


As an aside, I do see the data in the post:

[{"Name":"SAMPLE","ParentCode":"0X0","DateSentToRI":"2012-09-28CDT00:00:00","DateSignedDocSentToRI":"","ReinsurerCode":"1QO","TrackDates":true,"DateReceivedFromRI":"","NeverSigning":false,"ReinsurerContactName":"","ReinsurerContactID":"","id":null,"parentId":null,"leaf":true},{"Name":"SAMPLE":"0X0","DateSentToRI":"2012-09-28CDT00:00:00","DateSignedDocSentToRI":"","ReinsurerCode":"1QO","TrackDates":true,"DateReceivedFromRI":"","NeverSigning":false,"ReinsurerContactName":"","ReinsurerContactID":"","id":null,"parentId":null,"leaf":true}]

Class Sample:

Public Property DateSentToRI() As Date
Get
Return _dateSentToRI
End Get
Set(ByVal value As Date)
_dateSentToRI = value
End Set
End Property


Public Property DateReceivedFromRI() As Date
Get
Return _dateReceivedFromRI
End Get
Set(ByVal value As Date)
_dateReceivedFromRI = value
End Set
End Property

Public Property DateSignedDocSentToRI() As Date
Get
Return _dateSignedDocSentToRI
End Get
Set(ByVal value As Date)
_dateSignedDocSentToRI = value
End Set
End Property

Daniil
Sep 26, 2012, 6:39 AM
As an aside, I do see the data in the post:

[{"Name":"SAMPLE","ParentCode":"0X0","DateSentToRI":"2012-09-28CDT00:00:00","DateSignedDocSentToRI":"","ReinsurerCode":"1QO","TrackDates":true,"DateReceivedFromRI":"","NeverSigning":false,"ReinsurerContactName":"","ReinsurerContactID":"","id":null,"parentId":null,"leaf":true},{"Name":"SAMPLE":"0X0","DateSentToRI":"2012-09-28CDT00:00:00","DateSignedDocSentToRI":"","ReinsurerCode":"1QO","TrackDates":true,"DateReceivedFromRI":"","NeverSigning":false,"ReinsurerContactName":"","ReinsurerContactID":"","id":null,"parentId":null,"leaf":true}]


Is it a load or save request?

As far as I can understand it is a load request.

The default DateFormat of ModelField with Type="Date" is "yyyy-MM-ddTHH:mm:ss". So, please try to set your format.

Example

<ext:ModelField Name="date" Type="Date" DateFormat=""yyyy-MM-ddCDTHH:mm:ss"">

watteeuw
Sep 26, 2012, 8:03 AM
Sorry I'm interfering in this topic, but since the last few updates from SVN (v.2.1) the default Date format (Json serialized) starts to be UTC format
(yyyy-MM-ddUTCHH:mm:ss) instead of Json format (T). I didn't make such setting in ModelField.
Seems the T from format is replaced by: T: "Ext.Date.getTimezone(this)"
But this algo is not used in Json deserialization


Thanks!


Is it a load or save request?

As far as I can understand it is a load request.

The default DateFormat of ModelField with Type="Date" is "yyyy-MM-ddTHH:mm:ss". So, please try to set your format.

Example

<ext:ModelField Name="date" Type="Date" DateFormat=""yyyy-MM-ddCDTHH:mm:ss"">

Daniil
Sep 26, 2012, 8:31 AM
Hi @watteeuw,

I am unable to reproduce. Please demonstrate how you bind the data to the Store.

watteeuw
Sep 26, 2012, 9:54 AM
See in attached image the grid records (UTC format instead of column specified format)
but also in handler the string passed on inserting operation:
Data: [{"dt":"2012-09-26UTC11:47:08"}] Operation: Create
See below the code:

Default.aspx


<%@ Page Language="C#" %>

<%@ Import Namespace="System.Collections.Generic"%>
<%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>

<script runat="server">


protected void Page_Load(object sender, EventArgs e)
{
}


protected void TestStore_RefreshData(object sender, StoreReadDataEventArgs e)
{
this.TestList.DataBind();
}

</script>


<!DOCTYPE html >

<html >
<head runat="server">
<title>Test</title>
</head>
<body>
<ext:ResourceManager ID="ResourceManager1" runat="server" />


<ext:Button runat="server" Text="Test" >
<Listeners>
<Click Handler=" var rec=new testModel();
rec.data.dt= new Date();
#{GridPanel1}.store.insert(0, rec);
#{GridPanel1}.store.sync();
"/>
</Listeners>
</ext:Button>

<ext:GridPanel ID="GridPanel1"
runat="server"
Title="Testing"
Margins="0 0 5 5"
Region="East"
AutoDataBind="true"
Width="570"
Layout="FitLayout"
Frame="true">
<ColumnModel ID="ColumnModel1" runat="server">
<Columns>
<ext:Column ID="Col_date" runat="server" DataIndex="dt" Text="Date" Width="75" Format="ddd, dd-MM-yyyy" />
</Columns>
</ColumnModel>
<Store>
<ext:Store
ID="TestList"
runat="server"
ShowWarningOnFailure="true"
IsPagingStore="false"
OnRefreshData="TestStore_RefreshData"
OnReadData="TestStore_RefreshData">
<Proxy>
<ext:AjaxProxy Url="IISHandler1.ashx" >
<Reader>
<ext:JsonReader Root="data" SuccessProperty="success" MessageProperty="message" />
</Reader>
<Writer>
<ext:JsonWriter Encode="true" Root="data" />
</Writer>
</ext:AjaxProxy>
</Proxy>
<SyncParameters>
<ext:StoreParameter Name="action" Value="operation.action" Mode="Raw" />
</SyncParameters>
<Model>
<ext:Model ID="Model1" runat="server" Name="testModel" >
<Fields>
<ext:ModelField Name="dt" Type="Date"/>
</Fields>
</ext:Model>
</Model>
<Listeners>
<Exception Handler="Ext.Msg.alert('Operation failed', operation.getError());" />
<Write Handler="Ext.Msg.alert('Write', 'The data successfully saved');" />
</Listeners>
</ext:Store>
</Store>
<View>
<ext:GridView ID="GridView1" runat="server">
<GetRowClass Handler="return 'x-grid-row-expanded';" />
</ext:GridView>
</View>
<SelectionModel>
<ext:RowSelectionModel ID="RowSelectionModel1" runat="server" Mode="Single">
</ext:RowSelectionModel>
</SelectionModel>
<BottomBar>
<ext:PagingToolbar ID="PagingToolbar1" runat="server" StoreID="TestList" />
</BottomBar>

</ext:GridPanel>
</body>
</html>


Handler:

<%@ WebHandler Language="C#" Class="IISHandler1" %>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Globalization;
using Ext.Net;

[System.Web.Services.WebService(Namespace = "http://tempuri.org/")]
[System.Web.Services.WebServiceBinding(ConformsTo = System.Web.Services.WsiProfiles.BasicProfile1_1)]


public class TestClass
{
public TestClass(DateTime dt)
{
this.dt = dt;
}

public TestClass()
{
}

public DateTime dt { get; set; }
}

public class IISHandler1 : IHttpHandler
{


public bool IsReusable
{
get { return false; }
}

public void ProcessRequest(HttpContext context)
{

string action = context.Request["action"];
StoreResponseData sr = new StoreResponseData();

if (string.IsNullOrEmpty(action) || Store.Action(action) == StoreAction.Read)
{
TestClass cl =new TestClass();
sr.Data = JSON.Serialize(cl);
sr.Return();
return;
}


try
{
StoreDataHandler dataHandler = new StoreDataHandler(context);
string js = dataHandler.JsonData;
System.Diagnostics.Debug.WriteLine(String.Format("Data: {0} Operation: {1}", js, Store.Action(action)));
List<TestClass> dataList = JSON.Deserialize<List<TestClass>>(js);
sr.Data = JSON.Serialize(dataList);
sr.Return();
return;
}
catch (Exception e)
{
sr.Success = false;
sr.Message = e.Message;
}

sr.Return();
}

}

Daniil
Sep 26, 2012, 11:54 AM
There is no Format property of the common Column. Please use a DateColumn.

Also I was unable to reproduce the screenshot. I think updating from the SVN 2.1 branch will solve this problem.

watteeuw
Sep 26, 2012, 12:18 PM
Indeed DateColumn solved the store display but still have the error into handler when try to Deserialize the data.
Using last build 4373.
Which is your value in handler for js variable when you press Test button:
Data:
[{"dt":"2012-09-26T11:47:08"}] Operation: Create or
Data:
[{"dt":"2012-09-26UTC11:47:08"}] Operation: Create ?


There is no Format property of the common Column. Please use a DateColumn.

Also I was unable to reproduce the screenshot. I think updating from the SVN 2.1 branch will solve this problem.

adelaney
Sep 26, 2012, 2:11 PM
Danill,

No, this is not a request, but instead is an update POST. It is called via the store.sync() method and fires the update proxy API that I have configured. The JSON I pulled out was provided by inspecting the network detail in Firebug (in Firefox). I have not altered the date from the generated format from Ext. However, if you review my sample, you can see that the format actually does match what you stated as required.


Example

Code:

<ext:ModelField Name="date" Type="Date" DateFormat=""yyyy-MM-ddCDTHH:mm:ss"">

From Original Sample:


[{"Name":"SAMPLE","ParentCode":"0X0","DateSentToRI":"2012-09-28CDT00:00:00",...
"2012-09-28CDT00:00:00"

However, just to clarify, here is my controller function:

<HttpPost()> _
Public Function _EditReinsurerTree(ByVal ris As CWReinsurer()) As ActionResult
Dim rslt As New Ext.Net.MVC.StoreResult
'Need to wire up save.
rslt.Message = "Hello"

Return rslt
End Function

Here is the view (model portion):

.Model(Sub(mdl)
mdl.Add(Html.X().Model.Fields(Sub(fields)
fields.Add(Html.X.ModelField.Name("ID").Type(ModelFieldType.Int))
fields.Add(Html.X.ModelField.Name("Name"))
fields.Add(Html.X.ModelField.Name("ParentCode"))
fields.Add(Html.X.ModelField.Name("DateSentToRI").Type(ModelFieldType.Date))
fields.Add(Html.X.ModelField.Name("DateSignedDocSentToRI").Type(ModelFieldType.Date))
fields.Add(Html.X.ModelField.Name("ReinsurerCode"))
fields.Add(Html.X.ModelField.Name("TrackDates").Type(ModelFieldType.Boolean))
fields.Add(Html.X.ModelField.Name("DateReceivedFromRI").Type(ModelFieldType.Date))
fields.Add(Html.X.ModelField.Name("NeverSigning").Type(ModelFieldType.Boolean))
fields.Add(Html.X.ModelField.Name("ReinsurerContactName"))
fields.Add(Html.X.ModelField.Name("ReinsurerContactID"))
End Sub))
End Sub) _
Upon inspecting my "ris" variable, here is what I get (which is correct, as I updated 3 rows):

{Length=3}
(0): {Enterprise.Business.DocTracking.Web.Models.CWRein surer}
(1): {Enterprise.Business.DocTracking.Web.Models.CWRein surer}
(2): {Enterprise.Business.DocTracking.Web.Models.CWRein surer}

Upon inspecting ris(0):

{Enterprise.Business.DocTracking.Web.Models.CWRein surer}
_clientSigns: False
_contact: Nothing
_dateReceivedFromRI: #12:00:00 AM#
_dateSentToRI: #12:00:00 AM# _dateSignedDocSentToRI: #12:00:00 AM#
_hasNonConcurrentTerms: False
_id: 0
_name: "SAMPLE"
_neverSigning: False
_nonConcurrentTermsText: Nothing
_parent: Nothing
_parentCode: "0X0"
_reinsurerCode: "1QO"
_reinsurers: Nothing
_reinsurerSigns: False
_trackDates: True
_transmit: False
ClientSigns: False
CodeAndName: "SAMPLE"
Contact: {Enterprise.Business.DocTracking.Web.Models.Reinsu rerContact}
DateReceivedFromRI: #12:00:00 AM#
DateSentToRI: #12:00:00 AM#
DateSignedDocSentToRI: #12:00:00 AM#
HasNonConcurrentTerms: False
ID: 0
Name: "SAMPLE"
NeverSigning: False
NonConcurrentTermsText: Nothing
Parent: Nothing
ParentCode: "0X0"
ReinsurerCode: "1QO"
Reinsurers: Nothing
ReinsurerSigns: False
TrackDates: True
Transmit: False

So, again, my question is why would the dates be "null" and not automatically wired up like the rest of the data? And, to make matters worse, now that I am really going into depth for the sample for you, I see that "ID" is "null"(0) too when that data is part of the post as well:

Sample:

[{"ID":200010698,"Name":"SAMPLE":"0X0","DateSentToRI":"2012-09-22CDT00:00:00","DateSignedDocSentToRI":"","ReinsurerCode":"1QO","TrackDates":true,"DateReceivedFromRI":"","NeverSigning"...

(Just as an aside - none of my class properties are marked "ReadOnly")
Any suggestions?

Daniil
Sep 26, 2012, 8:26 PM
Indeed DateColumn solved the store display but still have the error into handler when try to Deserialize the data.
Using last build 4373.
Which is your value in handler for js variable when you press Test button:
Data:
[{"dt":"2012-09-26T11:47:08"}] Operation: Create or
Data:
[{"dt":"2012-09-26UTC11:47:08"}] Operation: Create ?

The first.

@adelaney and @watteeuw, seems, we discovered the problem. We are investigating a possible fix.

Please try to set:

DateFormat="yyyy-MM-dd\THH:mm:ss"
for the ModelField.

Does it resolve the problem?

Daniil
Sep 26, 2012, 9:50 PM
The fix has been committed to SVN. Please update. Does it resolve the problem on your side?

Also the getChangedData method for TreeStore has been implemented.

watteeuw
Sep 27, 2012, 6:32 AM
Hi Daniil,

Fix works, at least for me ! Checked with svn update

regards



The fix has been committed to SVN. Please update. Does it resolve the problem on your side?

Also the getChangedData method for TreeStore has been implemented.

Daniil
Sep 27, 2012, 6:55 AM
@watteeuw, thank you for confirming!