3

Page contains single form with input elements and jqgrid data. jqGrid data is retrieved in json using loadonce: true option. Data is edited locally.

How to submit all this data if submit button is pressed? Has jqGrid any method which can help to submit all data from all rows. jqGrid - How to edit and save multiple rows at once? mentions that jQuery ajax form plugin should be used but I havent found any sample.

jqGrid probably holds retrieved json table in element. In this case form plugin is not capable read this data.

How to get and submit all data retrieved using loadonce: true and edited?

Update1

Based on Oleg answer I tried:

function SaveDocument()  {
  var gridData = $("#grid").jqGrid('getGridParam','data');
  var postData = JSON.stringify(gridData);    
  $('#_detail').val( postData );
  var res = $("#Form").serializeArray();
  $.ajax({ type: "POST",        
  url: 'Edit'
  data : res
  });
   }
}

aspx page:

<form id="Form" class='form-fields'>
.... other form fields
<input name='_detail' id='_detail' type='hidden' />
</form>
<div id="grid1container" style="width: 100%">
   <table id="grid">
   </table>
</div>

In ASP.NET MVC2 Controller Edit method I tried to parse result using

public JsonResult Edit(string _detail) {

var order = new Order();
UpdateModel(order, new HtmlDecodeValueProviderFromLocalizedData(ControllerContext));

var serializer = new JavaScriptSerializer();
var details = serializer.Deserialize<List<OrderDetails>>>(_detail);
}

Exception occurs in Deserialize() call. Decimal and date properties are passed in localized format but it looks like Deserialize() does not parse localized strings and there is no way to force it to use converter like HtmlDecodeValueProviderFromLocalizedData passed to UpdateModel.

How to fix ? Is is reasonable/how to convert _detail parameter into NameValue collection and then use UpdateModel to update details, use some other deserialize or other idea ?

Update 2.

Decimal and Date CurrentUICulture values are present in form and in jqGrid data. Sample provided handles them in form OK but fails for jqGrid data. This controller should handle different entity types, form fields and jqgrid columns can defined at runtime. So using hard-coded names is not possible. Based on Oleg reply I tried to override decimal conversion by creating converter

public class LocalizedTypeConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new ReadOnlyCollection<Type>(new Type[] { typeof(decimal) });
        }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type,
            JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");
        if (type == typeof(decimal))
            return decimal.Parse(dictionary["resources"].ToString(), CultureInfo.CurrentCulture);
        return null;

    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new InvalidOperationException("We only Deserialize");
    }
}

But conversion still causes exception

0,0000 is not valid value for decimal. It looks like decimal converter cannot overridden. How to fix ?

Community
  • 1
  • 1
Andrus
  • 24,283
  • 56
  • 192
  • 347
  • u need normal form post or ajax post – Muhammad Adeel Zahid Jul 23 '11 at 09:17
  • @Muhammad: if error occurs, data in page should remain unchanged. If OK, redirect to page which retrieves updated order should returned. In second case it looks like normal post, in first like ajax post so probably ajax is required – Andrus Jul 23 '11 at 21:35

1 Answers1

8

First of all you can get all local data from the jqGrid with respect of

var localGridData = $("#list").jqGrid('getGridParam','data');

If you will need to send only subset of rows of the grid, like the selected rows only, you can need to get _index:

var idsToDataIndex = $("#list").jqGrid('getGridParam','_index');

To send the data to the server you can use the following function for example

var sendData = function(data) {
    var dataToSend = JSON.stringify(data);
    alert("The following data are sending to the server:\n" + dataToSend);
    $.ajax({
        type: "POST",
        url: "yourServerUrl",
        dataType:"json",
        data: dataToSend,
        contentType: "application/json; charset=utf-8",
        success: function(response, textStatus, jqXHR) {
            // display an success message if needed
            alert("success");
        },
        error: function(jqXHR, textStatus, errorThrown) {
            // display an error message in any way
            alert("error");
        }
    });
};

In the demo you will find a little more sophisticated example having two buttons: "Send all grid contain", "Send selected rows". The corresponding code is below

$("#sendAll").click(function(){
    var localGridData = grid.jqGrid('getGridParam','data');
    sendData(localGridData);
});
$("#sendSelected").click(function(){
    var localGridData = grid.jqGrid('getGridParam','data'),
        idsToDataIndex = grid.jqGrid('getGridParam','_index'),
        selRows = grid.jqGrid('getGridParam','selarrrow'),
        dataToSend = [], i, l=selRows.length;
    for (i=0; i<l; i++) {
        dataToSend.push(localGridData[idsToDataIndex[selRows[i]]]);
    }
    sendData(dataToSend);
});

where

var grid = $("#list"),
    decodeErrorMessage = function(jqXHR, textStatus, errorThrown) {
        var html, errorInfo, i, errorText = textStatus + '\n<br />' + errorThrown;
        if (jqXHR.responseText.charAt(0) === '[') {
            try {
                errorInfo = $.parseJSON(jqXHR.responseText);
                errorText = "";
                for (i=0; i<errorInfo.length; i++) {
                   if (errorText.length !== 0) {
                       errorText += "<hr/>";
                   }
                   errorText += errorInfo[i].Source + ": " + errorInfo[i].Message;
                }
            }
            catch (e) { }
        } else {
            html = /<body.*?>([\s\S]*)<\/body>/i.exec(jqXHR.responseText);
            if (html !== null && html.length > 1) {
                errorText = html[1];
            }
        }
        return errorText;
    },
    sendData = function(data) {
        var dataToSend = JSON.stringify(data);
        alert("The following data are sending to the server:\n"+dataToSend);
        $.ajax({
            type: "POST",
            url: "yourServerUrl",
            dataType:"json",
            data: dataToSend,
            contentType: "application/json; charset=utf-8",
            success: function(response, textStatus, jqXHR) {
                // remove error div if exist
                $('#' + grid[0].id + '_err').remove();
                alert("success");
            },
            error: function(jqXHR, textStatus, errorThrown) {
                // remove error div if exist
                $('#' + grid[0].id + '_err').remove();
                // insert div with the error description before the grid
                grid.closest('div.ui-jqgrid').before(
                    '<div id="' + grid[0].id + '_err" style="max-width:' + grid[0].style.width +
                    ';"><div class="ui-state-error ui-corner-all" style="padding:0.7em;float:left;"><span class="ui-icon ui-icon-alert" ' +
                    'style="float:left; margin-right: .3em;"></span><span style="clear:left">' +
                    decodeErrorMessage(jqXHR, textStatus, errorThrown) + '</span></div><div style="clear:left"/></div>');
            }
        });
    };

I think, that more difficult and more complex problem you will become on the server. In case of concurrency errors, but I wrote you about the problems before. Exactly because of the problems I personally would never implement saving of multiple rows on the server.

UPDATED: To get data from the form you can use jQuery.serialize. You should use name attribute for all fields in the form which you want to serialize. All data which you need to send are

var allData = {
    localGridData: grid.jqGrid('getGridParam','data'),
    formData: $("#formid").serialize()
};

You can send the data exactly like I described before: sendData(allData).

Oleg
  • 219,533
  • 32
  • 395
  • 775
  • @Andrus: I forget that you need to send the form data additionally to the grid data. So I updated my answer. – Oleg Jul 23 '11 at 14:07
  • thank you. 3 issues: 1. How to parse returned json in server ? ASP .NET JavaScriptSerializer() throws exception since json contains point as decimal separator and dates in local format 2. How to update order from form data and order details from jqGrid data sent by this method in server ? ASP .NET MVC2 UpdateModel() requires data to be passed as key/value pairs, this passes in json 3. In other answers you recommended to `use var gridData = jQuery("#grid").getRowData()`. Which method is better? – Andrus Jul 23 '11 at 21:46
  • @Andrus: The contain of jqGrid contain depend on the JSON data which you send from the server during the filling of the jqGrid. You can do all so that you will have no problem with any kind of parsing of the JSON data. I don't understand why the order of form elements can be important. `getRowData` get the data from the current page as the formatted strings. The `data` gives jqGrid data from all local pages in the raw format. – Oleg Jul 23 '11 at 21:57
  • 1
    @Andrus: You don't included the code for jqGrid and the form which you serialize. So it is unclear for me **where the decimal and date properties exist**. Are there exist in the grid or in the form? The example of the JSON data could explain also many things. Are the numbers and dates will be send as strings? In the case you can't use `serializer.Deserialize>>` directly. Instead of that you should define **helper class** like `OrderDetailsWithStrings` having other types of the properties. Alternative you can use `JavaScriptConverter`. – Oleg Jul 24 '11 at 07:36
  • 1
    @Andrus: See [here](http://stackoverflow.com/questions/3226568/use-attr-tags-for-json/3228858#3228858) an example of the usage of the `JavaScriptConverter`. – Oleg Jul 24 '11 at 07:39
  • Than you. decimal and date values are present both in form and in jqGrid. Problably they are sent as string by JSON.Stringify I updated question. – Andrus Jul 24 '11 at 08:20
  • there may be 2 solutions: 1. Create new provider , pass json to it and use `UpdateModel( OrderDetails, new() JsonValueProviderFromLocalizedData(details) )` to update 2. Use some other javascriptdeserializer if such exists. Which is best solution ? – Andrus Jul 24 '11 at 08:26
  • 1
    @Andrus: It is difficult to gives you any recommendation in the question because I don't know the data which you has. Probably it is easier to make some modification of the data in JavaScript code **before** the `JSON.stringify` call. For example you can easy replace '.' to ',' or convert date format. It could solve your problem in more easy way. – Oleg Jul 24 '11 at 08:50
  • thank you. Is it best way in client side to loop over date and decimal columns whose type in colModel is number or date and convert them to Invariant culture before sending?Or is it better to use formatter/unformatter for every number and date column to keep them stored in invariant culture ? Where to find such sample ? – Andrus Jul 24 '11 at 09:26
  • @Andrus: I can only repeat that to answer on your question one need to have the input data which you use to fill the jqGrid contain. The contain of the `data` depend on this. It you would send the data in another format and use another `formatter` options the problem which you has can not exist at all. Could you include the test JSON data and the `jsonReader`? Do you use `repeatitems: true` or `repeatitems: false`? Which format has the **input** numbers and dates which you send from the server? – Oleg Jul 24 '11 at 10:53
  • thank you. Based on your great suggestion I started to re-write application so that every row is saved immediately and try to use virtual scrolling with scroll:1 . In this case local data is not used but similar issue sill occurs. I posted this in http://stackoverflow.com/questions/6809903/jqgrid-how-to-save-order-data-with-order-detail-row . I marked your answer as answer and upvoted your replies. – Andrus Jul 24 '11 at 21:41