4

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

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

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

            return Refresh(vm);
     }

我的邮政编码将屏幕上的表单序列化,并将其与刚刚更改的字段的新旧值一起发布。在动作参数中正确设置了旧值和新值参数,但控制器动作中的 vm 参数始终为空。控制器 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
    });

}

将其与单击某个字段时正在处理的同一屏幕上的以下内容进行对比:

控制器动作:

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 为空。在第二个单击的示例中,使用序列化表单正确设置了 vm。

formActionUrl 参数对两者都是相同的,这不是问题,因为我调试了帖子,我能看到的唯一区别是第一个示例(更改事件)中的请求正文,vm 参数看起来是 URL 编码的:

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。评论%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=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

我试图通过将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=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.添加日期时间=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 的解决方案之一,看看我是否可以让它工作,但可能没有时间。

4

3 回答 3

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



更新

方法二

尽管上述解决方案适用于您的情况(因为它适用于我的类似情况),但这里还有另一种处理方式。

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

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

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

即在 JSON 对象中,您将序列化的表单添加为vm. 这就是为什么你vm在你的操作中得到一个空值oldVal并且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 插件来为你做这件事。

您需要做的就是关注

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

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

希望这可以帮助

于 2013-07-23T09:35:31.270 回答
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
    });

您对操作的第一个参数不为空,但其属性为空(即 vm 不为空,但 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 表单并找到了这个(使用 jQuery 将表单数据转换为 JavaScript 对象).. 然后我一起捏造了这个:

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 将其与您想要传回的其他属性“合并”。

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

于 2013-09-09T14:45:00.827 回答
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 

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

于 2013-09-09T15:20:55.430 回答