I am trying to post parameters to a controller action when a field changes via AJAX but finding the first parameter is always null.
The controller action I am trying to post to is:
public ActionResult Model_GroupCompanyIDChanged(ActionViewModel vm, int oldVal, int newVal)
{
vm.Model.Observation = "Changed from " + oldVal + " to " + newVal;
return Refresh(vm);
}
My post code serializes the form on the screen and posts it along with the old and new values for the field that just changed. The old and new value parameters are being set correctly in the action parameters but the vm parameter is always null in the controller action. There are no issues with the controller URL as I can debug the action and see it is called.
function ChangeRefreshScreen(ControllerURL, formActionUrl, oldVal, newVal) {
var origModel = $("form[action='" + formActionUrl + "']").serialize();
var data = {
"oldVal": oldVal
, "newVal": newVal
, "vm": origModel
};
RefreshScreenPassData(ControllerURL, formActionUrl, data);
}
function RefreshScreenPassData(ControllerURL, formActionUrl, data) {
alert(data);
$.ajax({
url: ControllerURL,
type: 'POST',
data: data,
success: function (response) {
RefreshScreenContent(response);
},
error: AjaxError
});
}
Contrast that to the following on the same screen which IS working for handling when a certain field is clicked:
Controller Action:
public ActionResult Model_ActionDateClicked(ActionViewModel vm)
{
vm.Model.Observation = "Clicked";
return Refresh(vm);
}
JavaScript (Uses same RefreshScreenPassData function from above to do the actual POST):
function ElementClickedRefresh(ControllerURL, formActionUrl) {
var origModel = $("form[action='" + formActionUrl + "']").serialize();
RefreshScreenPassData(ControllerURL, formActionUrl, $("form[action='" + formActionUrl + "']").serialize());
}
In a nutshell the first change event sample first sets the parameters into an object since there is more than one parameter and only the old and new int parameters are set server side with the ViewModel vm being null. In the second clicked sample the vm is set correctly using the serialized form.
The formActionUrl parameter is the same for both and isn't the problem because I debugged the posts and the only difference I can see is for the request body in the first sample (change event) the vm parameter looks URL encoded:
oldVal=0&newVal=02&vm=__RequestVerificationToken%3DoeQx0RyQ-nOPQ1namoIeRuAWRzfVltfPx5ntsdpuaFTSdADuG_eC__Y54hlWmf8AOAigvyH8R_6qP77bJr1Mm5Yag7a7R9oSQse6e9NJMYg1%26ViewMode%3DEdit%26Model.ActionDate%3D11%252F07%252F2013%2B09%253A32%253A08%26Model.Observation%3DClicked%26Model.OriginatorUserID%3D1%26Model.ActiononUserID%3D0%26Model.ActionStatusID%3D1%26Model.ActionTypeID%3D0%26Model.ClientID%3D23%26Model.ClientContactID%3D0%26Model.PriorityID%3D0%26Model.CloseOutDate%3D%26Model.ActionNotes%3D%26Model.ProgressNotes%3D%26Model.Comments%3D%26Model.BusinessUnitID%3D0%26Model.GroupCompanyID%3D02%26Model.Confidential%3Dfalse%26Model.Id%3D1%26Model.Archived%3Dfalse%26Model.AddedUserID%3D1%26Model.AddedDateTime%3D11%252F07%252F2013%2B09%253A32%253A19%26Model.ModifiedUserID%3D1%26Model.ModifiedDateTime%3D11%252F07%252F2013%2B09%253A32%253A19
but for the second clicked event which is working it is not:
__RequestVerificationToken=oeQx0RyQ-nOPQ1namoIeRuAWRzfVltfPx5ntsdpuaFTSdADuG_eC__Y54hlWmf8AOAigvyH8R_6qP77bJr1Mm5Yag7a7R9oSQse6e9NJMYg1&ViewMode=Edit&Model.ActionDate=11%2F07%2F2013+09%3A32%3A08&Model.Observation=Changed&Model.OriginatorUserID=1&Model.ActiononUserID=0&Model.ActionStatusID=1&Model.ActionTypeID=0&Model.ClientID=23&Model.ClientContactID=0&Model.PriorityID=0&Model.CloseOutDate=&Model.ActionNotes=&Model.ProgressNotes=&Model.Comments=&Model.BusinessUnitID=0&Model.GroupCompanyID=0&Model.Confidential=false&Model.Id=1&Model.Archived=false&Model.AddedUserID=1&Model.AddedDateTime=11%2F07%2F2013+09%3A32%3A19&Model.ModifiedUserID=1&Model.ModifiedDateTime=11%2F07%2F2013+09%3A32%3A19
I tried to set my parameter string manually by changing the javascript to :
function ChangeRefreshScreen(ControllerURL, formActionUrl, oldVal, newVal) {
var origModel = $("form[action='" + formActionUrl + "']").serialize();
var data = "oldVal=" + oldVal + "&newVal=" + newVal + "&vm=" + origModel
RefreshScreenPassData(ControllerURL, formActionUrl, data);
}
and the POST request body changes to
oldVal=02&newVal=023&vm=__RequestVerificationToken=xiYEcz53UNPVoGZ3RQGO_HFn54LIu0bTjQB-PB13tTEWZ7vUHMbsW25s7rI7D7lBLtACutEpynoNnk66jxijzSzFMCBO_nDoXf_FqsR9Cc81&ViewMode=Edit&Model.ActionDate=11%2F07%2F2013+09%3A32%3A08&Model.Observation=Clicked&Model.OriginatorUserID=1&Model.ActiononUserID=0&Model.ActionStatusID=1&Model.ActionTypeID=0&Model.ClientID=23&Model.ClientContactID=0&Model.PriorityID=0&Model.CloseOutDate=&Model.ActionNotes=&Model.ProgressNotes=&Model.Comments=&Model.BusinessUnitID=0&Model.GroupCompanyID=023&Model.Confidential=false&Model.Id=1&Model.Archived=false&Model.AddedUserID=1&Model.AddedDateTime=11%2F07%2F2013+09%3A32%3A19&Model.ModifiedUserID=1&Model.ModifiedDateTime=11%2F07%2F2013+09%3A32%3A19
but it still does not bind the view model parameter.
What am I doing wrong that isn't setting the parameter when it comes from a JavaScript object?
UPDATE 1
I have tried manually calling JSON stringify in an attempt to get this working but it still doesn't work:
function ChangeRefreshScreen(ControllerURL, formActionUrl, oldVal, newVal) {
var origModel = $("form[action='" + formActionUrl + "']").serialize();
var data = "oldVal=" + oldVal + "&newVal=" + newVal + "&vm=" + JSON.stringify(origModel)
RefreshScreenPassData(ControllerURL, formActionUrl, data);
}
UPDATE 2
The following worked for me where it adds the old and new vals to the form but needs to remove them again otherwise the next time they end up in the form more than once which screws the old and new vals:
function ChangeRefreshScreen(ControllerURL, formActionUrl, oldVal, newVal) {
var $myForm = $("form[action='" + formActionUrl + "']");
$myForm.append("<input type='hidden' name='oldVal' value='" + oldVal + "' id='oldVal' />");
$myForm.append("<input type='hidden' name='newVal' value='" + newVal + "' id='newVal' />");
var origModel = $myForm.serialize();
RefreshScreenPassData(ControllerURL, formActionUrl, origModel);
$('#oldVal').remove();
$('#newVal').remove();
}
It would be better to not add the elements to the DOM but at least it's a small piece of code and is not CPU intensive. I am still hoping to take another attempt at one of Gordatron's solutions and see if I can get it working but may not have time.