AJAX Post to Controller未正确设置VIewModel参数

时间:2013-07-23 09:24:34

标签: javascript ajax asp.net-mvc jquery

我试图在通过AJAX更改字段时将参数发布到控制器操作,但查找第一个参数始终为null。

我想发布的控制器操作是:

public ActionResult Model_GroupCompanyIDChanged(ActionViewModel vm, int oldVal, int newVal)
     {
            vm.Model.Observation = "Changed from " + oldVal + " to " + newVal;

            return Refresh(vm);
     }

我的帖子代码序列化了屏幕上的表单,并将其与刚刚更改的字段的旧值和新值一起发布。在操作参数中正确设置旧值和新值参数,但控制器操作中的vm参数始终为null。控制器URL没有问题,因为我可以调试操作并看到它被调用。

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
    });

}

在点击某个字段时,IS工作处理的同一屏幕上与以下内容形成对比:

控制器操作:

public ActionResult Model_ActionDateClicked(ActionViewModel vm)
        {
            vm.Model.Observation = "Clicked";

            return Refresh(vm);
        }

JavaScript(使用上面的相同RefreshScreenPassData函数进行实际的POST):

function ElementClickedRefresh(ControllerURL, formActionUrl) {
    var origModel = $("form[action='" + formActionUrl + "']").serialize();
    RefreshScreenPassData(ControllerURL, formActionUrl, $("form[action='" + formActionUrl + "']").serialize());
}

简而言之,第一个更改事件示例首先将参数设置为一个对象,因为有多个参数,并且只有旧的和新的int参数设置为服务器端且ViewModel vm为null。在第二个单击的示例中,使用序列化表单正确设置了vm。

formActionUrl参数对于两者都是相同的并且不是问题,因为我调试了帖子,我可以看到的唯一区别是第一个示例中的请求主体(更改事件)vm参数看起来是URL编码的:< / p>

  

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

但是对于正在运行的第二个点击事件,它不是:

  

__ RequestVerificationToken = oeQx0RyQ-nOPQ1namoIeRuAWRzfVltfPx5ntsdpuaFTSdADuG_eC__Y54hlWmf8AOAigvyH8R_6qP77bJr1Mm5Yag7a7R9oSQse6e9NJMYg1&安培; VIEWMODE =编辑&安培; Model.ActionDate = 11%2F07%2F2013 + 09%3A32%3A08&安培; Model.Observation =更改&安培; 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 =假安培; Model.Id = 1&安培; Model.Archived =假安培; Model.AddedUserID = 1&安培; Model.AddedDateTime = 11%2F07%2F2013 + 09%3A32 %3A19&安培; Model.ModifiedUserID = 1&安培; Model.ModifiedDateTime = 11%2F07%2F2013 + 09%3A32%3A19

我尝试通过将javascript更改为:

手动设置我的参数字符串
function ChangeRefreshScreen(ControllerURL, formActionUrl, oldVal, newVal) {
    var origModel = $("form[action='" + formActionUrl + "']").serialize();
    var data = "oldVal=" + oldVal + "&newVal=" + newVal + "&vm=" + origModel
    RefreshScreenPassData(ControllerURL, formActionUrl, data);
}

并且POST请求正文更改为

  

OLDVAL = 02&安培;的newval = 023&安培; VM = __ RequestVerificationToken = xiYEcz53UNPVoGZ3RQGO_HFn54LIu0bTjQB-PB13tTEWZ7vUHMbsW25s7rI7D7lBLtACutEpynoNnk66jxijzSzFMCBO_nDoXf_FqsR9Cc81&安培; VIEWMODE =编辑&安培; Model.ActionDate = 11%2F07%2F2013 + 09%3A32%3A08&安培; Model.Observation =已点击&安培; 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 =安培;模型.ProgressNotes =安培; Model.Comments =安培; Model.BusinessUnitID = 0&安培; Model.GroupCompanyID = 023&安培; Model.Confidential =假安培; Model.Id = 1&安培; Model.Archived =假安培; Model.AddedUserID = 1&安培; Model.AddedDateTime = 11%2F07%2F2013 + 09%3A32%3A19&安培; Model.ModifiedUserID = 1&安培; Model.ModifiedDateTime = 11%2F07%2F2013 + 09%3A32%3A19

但它仍然没有绑定视图模型参数。

我做错了什么,当它来自JavaScript对象时没有设置参数?

更新1

我尝试过手动调用JSON stringify以尝试使其正常工作,但它仍然不起作用:

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);
}

更新2

以下是为我工作的地方,它将旧的和新的val添加到表单中,但是需要再次删除它们,否则下次它们最终会以不止一次的形式结束,这会使新旧val发生错误:

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();

}

最好不要将元素添加到DOM中,但至少它只是一小段代码而且不是CPU密集型的。我仍然希望再次尝试使用Gordatron的一个解决方案,看看我是否可以使其工作但可能没有时间。

3 个答案:

答案 0 :(得分:1)

方法1

似乎篡改表单数据对您不起作用。

您如何尝试以下

function ChangeRefreshScreen(ControllerURL, formActionUrl, oldVal, newVal) {
    var $myForm = $("form[action='" + formActionUrl + "']");
    $myForm.append("<input type='hidden' name='oldVal' value='" + oldVal + "' />");
    $myForm.append("<input type='hidden' name='newVal' value='" + newVal + "' />");
    var origModel = $myForm.serialize();
    RefreshScreenPassData(ControllerURL, formActionUrl, origModel);
}


<小时/> 的更新

方法2

虽然上述解决方案适用于您的情况(因为它与我的情况类似),但还有另一种方法可以做到这一点。

将数据发布到服务器有两种格式。一种是表单编码,您使用$("form[action='" + formActionUrl + "']").serialize()实现,另一种是使用JSON。

在上面的问题中,您使用了两者的混合

var data = {
    "oldVal": oldVal,
    "newVal": newVal,
    "vm": origModel
};

即。在JSON对象中,您要将序列化表单添加为vm。这就是为什么在vmoldVal被正确填充的情况下,您在newVal中获得空值的原因。

我建议如果你不想在我的回答中使用上面提供的解决方案,你应该采用JSON方法。即使用您的表单值创建一个JSON对象并使用

发布
$.ajax({
    type: 'POST',
    url: ControllerURL,
    contentType: "application/json",
    data: JSON.stringify(data),   
    success: function (response) {
         RefreshScreenContent(response);
    },
    error: AjaxError
});

注意:contentType: "application/json"

我知道使用id / names获取表单的所有值并创建一个JSON对象会有点令人筋疲力尽,但幸运的是,我写了一些小toJSON plugin,这对你来说就是这样。

您需要做的就是关注

var form = $("form[action='" + formActionUrl + "']").toJSON();

var data = {
    "oldVal": oldVal,
    "newVal": newVal,
    "vm": form 
};

希望这有帮助

答案 1 :(得分:1)

我做了一点测试,看看我是否可以重新创建你的问题。我成功了,我设法让它上班,但我不知道它是最好的方式来做它或你想要的。

要重新创建它,我创建了一个测试应用并添加了模型:

public class Item {
    public string id {get;set;}
    public string name { get; set; }
}

观点:

<h2>Test</h2>
@using(Html.BeginForm()){

@Html.EditorFor(Model => Model.id)

@Html.EditorFor(Model => Model.name)

}

使用js:

$(function () {

    var origModel = $("form").serialize();
    var data = {
        "oldVal": 'old'
        , "newVal": 'new'
        , "vm": origModel
    };

    RefreshScreenPassData("/Home/Test", data);
});

function RefreshScreenPassData(ControllerURL, data) {
    alert(data);
    $.ajax({
        url: ControllerURL,
        type: 'POST',
        data: data,
        dataType:'json',
        success: function (response) {
            RefreshScreenContent(response);
        },
        error: AjaxError
    });

}

function AjaxError(e) {
    alert(e);
}

控制器:

    [HttpGet]
    public ActionResult Test() {
        return View(new Item() { id = "1", name = "name" });
    }

    [HttpPost]
    public ActionResult Test(Item vm, string oldVal,string  newval) {
        return View(new Item() { id = vm.id+"oo", name = vm.name+"000" });
    }

我发现了什么:

手动提交此不起作用

$.ajax({
        url: ControllerURL,
        type: 'POST',
        data: {
                "oldVal": 'old'
            , "newVal": 'new'
            , "vm": {"id":"1","name":"name"}
            },
        success: function (response) {
            RefreshScreenContent(response);
        },
        error: AjaxError
    });

你对动作的第一个参数不是null但是它的属性是null(即vm不是null但是vm.id和vm.name是)

工作

 $.ajax({
        url: ControllerURL,
        type: 'POST',
        data: {
                "oldVal": 'old'
            , "newVal": 'new'
            , "id": "1"
            , "name": "name"
            },
        success: function (response) {
            RefreshScreenContent(response);
        },
        error: AjaxError
    });

下一个问题:

表单上的.serialise方法返回url参数类型字符串:

id=1&name=name

不是json。所以我很快就找到了一种方法来获得json形式的表格并找到了这个(Convert form data to JavaScript object with jQuery)..所以我随后一起捏造了这个:

jQuery(function () {

    var data = {
        "oldVal": 'old'
        , "newVal": 'new'

    };

    var o = {};
    var a = $("form").serializeArray();

    $.each(a, function () {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });

    jQuery.extend(data, o);

    RefreshScreenPassData("/Home/Test", data);
});

function RefreshScreenPassData(ControllerURL, data) {
    alert(JSON.stringify(data));
    $.ajax({
        url: ControllerURL,
        type: 'POST',
        data: data,
        success: function (response) {
            alert(response);
        },
        error: AjaxError
    });

}

它只是将表单转换为对象,然后使用extend将其与要传回的其他属性“合并”。

这不是你问题的真正解决方案,但我希望它足以让你继续前进。

答案 2 :(得分:0)

其他选项不发送json ..只是序列化。

模型:

public class Item {
    public string id {get;set;}
    public string name { get; set; }
}

视图模型:

public class ViewModel {
    public Item model { get; set; }
    public String CapsName { get { return this.model.name.ToUpper(); } }
    public String OtherField { get; set; }
}

控制器:

    [HttpGet]
    public ActionResult Test2() {
        return View("ViewModelTest",new ViewModel() { 
                                  model = new Item() {
                                           id = "1"
                                           , name = "name" 
                                       }
                                  , OtherField="bubba"});
    }

    [HttpPost]
    public ActionResult Test2(ViewModel vm, string oldVal, string newval) {
        return View(new Item() { 
                      id = vm.model.id + "oo"
                       , name = vm.model.name + "000" 
                      });
        //pointless code to allow me to put in a break point
    }

查看:

    @using(Html.BeginForm()){

        @Model.CapsName<br />

        @Html.EditorFor(m => m.model.id)

        @Html.EditorFor(m => m.model.name)

        @Html.EditorFor(m=>m.OtherField)
        }

JS:

        jQuery(function () {

            var data = {
                "oldVal": 'old'
                , "newVal": 'new'
            };
            RefreshScreenPassData("/Home/Test2", 
                        $.param(data) + "&" 
                        + $("form").serialize());
        });


        function RefreshScreenPassData(ControllerURL, data) {
            alert(data);
            $.ajax({
                url: ControllerURL,
                type: 'POST',
                data: data,
                success: function (response) {
                    alert(response);
                },
                error: AjaxError
            });

        }

此帖发布的数据为:

oldVal=old&newVal=new&model.id=1&model.name=name&OtherField=bubba 

然后断点被击中我有一个完整的viewmodel,模型以及预期的旧值和新值。