MVC的表单(form)绑定到数据模型上

参考网址:

列表类的绑定:https://www.cnblogs.com/mrtiny/p/5807489.html
js获取表单数据:https://www.jb51.net/article/90756.htm
ajax提交表单数据:https://blog.csdn.net/CrackLibby/article/details/80013057

在mvc中,表单的输入字段绑定到数据模型上的过程是自动完成的,本文进行简单地说明。

注:我用的是vs2015,mvc5,测试用的是360浏览器

我的目标是在一个页面上,弹出来一组输入项(form表单),用户在输入后点提交时,后台能够获取到输入的内容。如果所有处理成功,就刷新页面,使输入的内容更新到页面上(此时弹出的输入项会被隐藏),如果失败,就保持当前的状态。这样做有个好处是,如果失败,则当前的页面完成保持当前的输入状态,没有任务改变,也没有任何刷新,感受会好很多。

为了实现这个目标,需要有几个步骤:

1. 这个表单在页面加载时处于隐藏状态,在点击一个功能按钮时,显示这个表单。这个步骤简单,后面就不说了
2. 点击表单中的“提交”按钮时,用js获取表单的输入数据,然后使用ajax提交数据
3. 后台收到提交的数据时进行处理,并返回处理结果
4. ajax收到处理结果后,如果是失败就进行提示,如果成功,就刷新页面

一个一个步骤来。

2.1. 用js获取表单中输入的数据

参数前面的网址,直接使用就行了,但是那个网址中的代码少了对select输入的处理,所以我这里对它进行了少许修改,修改后的代码如下:

// https://www.jb51.net/article/90756.htm
//获取指定form中的所有的<input>对象  
function getFormElements(formId) {
    var form = Gho(formId);
    var elements = new Array();
    var tagElements = form.getElementsByTagName('input');
    for (var j = 0; j < tagElements.length; j++) {
        elements.push(tagElements[j]);
    }

    tagElements = form.getElementsByTagName('select');
    for (var j = 0; j < tagElements.length; j++) {
        elements.push(tagElements[j]);
    }
    return elements;
}

//获取单个input中的【name,value】数组 
function checkboxSelector(element, hoId) {
    if (element.checked)
        return [hoId, element.value];
}

// 单个select的选中项
function selectSelector(element, hoId) {
    for (var i = 0; i < element.length; i++)
    {
        if (element[i].selected == true)
            return [hoId, element[i].value];
    }
}

function getFormInput(element) {
    var hoId = element.name;
    if (hoId == null || hoId == "")
        hoId = element.id;
    if (hoId == null || hoId == "")
    {
        return null;
    }
    switch (element.type.toLowerCase()) {
        case 'submit':
        case 'hidden':
        case 'password':
        case 'text':
            return [hoId, element.value];
        case 'checkbox':
        case 'radio':
            return checkboxSelector(element, hoId);
        case 'select-one':
            return selectSelector(element, hoId);
    }
    return false;
}

/*
组合URL 
*/
function serializeElement(element) {
    var method = element.tagName.toLowerCase();
    var parameter = getFormInput(element);
    if (parameter == null)
        return;

    if (parameter) {
        var key = encodeURIComponent(parameter[0]);
        if (key.length == 0) return;

        if (parameter[1].constructor != Array)
            parameter[1] = [parameter[1]];

        var values = parameter[1];
        var results = [];
        for (var i = 0; i < values.length; i++) {
            results.push(key + '=' + encodeURIComponent(values[i]));
        }
        return results.join('&');
    }
}

//调用方法   
function serializeForm(formId) {
    var elements = getFormElements(formId);
    var queryComponents = new Array();

    for (var i = 0; i < elements.length; i++) {
        var queryComponent = serializeElement(elements[i]);
        if (queryComponent)
            queryComponents.push(queryComponent);
    }

    return queryComponents.join('&');
}

除了添加selectSelector()之外,对函数的名称进行了修改,key由单一的元素名称修改成了元素的名称和ID号二选一。

调用serializeElement()之后,输出的就是用 & 号连接起来的经过url编码的键值对了,所以它可以直接放在 url 的后面做为参数,即 http://serverip/mytask?<formdata>
其中的 <formdata> 表示 serializeElement() 的返回数据

2.2 用ajax提交数据

先看js代码:

function AddProperty_Submit()
{
    var formData = "";
    formData = serializeForm("prpAddForm");

    var errMsg = "";
    var curUrl = GetPageUrlBase(false);
    var urlString = curUrl + 'AddProperty';
    urlString += "?" + formData;
    $.ajax(
        {
            type: "POST",
            url: urlString,
            contentType: "text/javascript",    // request的数据类型是json
            dataType: "json",                   // 返回的数据类型是json
            //data: formData,
            beforeSend: function () {
                // 发送之前会进入到这个函数中,如果返回了false,就不会发送了
                //return false;
                return true;
            },

            success: function (data) {
                // 由于上面设置了"json",所以这里的data就是一个json对象了,服务器返回{}时,这里不会进到此函数中
                // 所以一旦进来,就说明确实拿到了标定的json数据
                g_isAddSubmited = false;
                if (data == null || data == "" || data == "{}") {
                    errMsg = "未知错误,请重试";
                    alert(errMsg);
                    return;
                }

                if (data["opeResult"] == 0) {
                    // 提交成功,就刷新页面
                    location.reload(true);
                    return;
                }

                // 失败
                errMsg = data["errmsg"];
                alert(errMsg);
            },

            error: function (errMsg) {
                console.log(errMsg);
            }
        });
}

本来我以为应该是要把表单数据放在 data 项中,但实际上我那样它不成功,而是应该放在url的参数里。最后的url类似这样的格式:
http://serverip/AddProperty?name=aa&defval=bb

其中 AddProperty 是control中的对应action,由于这个action是在js中指定的,所以html表单中指定的action名称就没啥重要的了。

这里要说明的一个情况,因为这个表单是在一个页面上的,而这个页面上可能存在多个表单,还有就是这个页面绑定的数据模型不是这个表单所要求的,同时因为多个表单也不可能强绑定多个数据模型,所以从表单上来说,没办法直接指定要绑定的数据模型。

3. 后台对数据的处理

为了方便,action的参数还是要采用数据模型会方便很多,对程序维护会非常有利,所以还是往这方面去靠。

经过上面的网址来看,似乎并不难,只要数据模型的字段名称和表单的字段表名一样就可以了。数据模型定义如下(其实这里应该简化一下能够说明问题就行了,但那样要改来改去的,所以我就把这个输入的所有内容全部贴出来了,省得改):

    public class PropertyAddViewModeo
    {
        // 添加列表类的绑定值:https://www.cnblogs.com/mrtiny/p/5807489.html

        // 只对修改有效
        public int prpId { get; set; }

        [Display(Name = "显示名称")]
        public string prpDesc { get; set; }

        // 键名
        [Display(Name = "字段名称")]
        public string prpName { get; set; }

        // 输入方式
        public int prpSubType { get; set; }

        public string prpValues { get; set; }
        public string prpDefValue { get; set; }
        public List<int> toPrpGroup { get; set; }
    }

这里除了最后一个toPrpGroup之外,其它的都简单,表单如下代码(注:为了减少代码,这里简化了一些无关的辅助内容,以及排版代码):

<div id="divPrpAdd" style="display:none;position:absolute;z-index:1;background-color:honeydew;width:800px;min-height:600px;border:1px solid black;padding:8px;">
    @using (Html.BeginForm("AddProperty", "Manage", FormMethod.Post, new { id = "prpAddForm" }))
    {
        <input type="hidden" name="prpId" id="prpId" value="" />
		<label>属性名称:</label>		<input type="text" name="prpDesc" id="prpDesc" />
		<label>字段名称:</label>		<input type="text" name="prpName" id="prpName" />
		<label>输入方式:</label>
		<select name="prpSubType" id="prpSubType">
			<option value="0">输入</option>
			<option value="1" selected>选择</option>
		</select>
		<label>属性值列表:</label>		<input type="text" name="prpValues" id="prpValues" />
		<label>缺省值:</label>		<input type="text" name="prpDefValue" id="prpDefValue" />
		<label>加入到属性组:</label>
		<div id="prpGroupList">
			<input type="checkbox" id="toPrpGroup[0]" name="toPrpGroup[0]" value="3">
			<input type="checkbox" id="toPrpGroup[1]" name="toPrpGroup[1]" value="4">
		</div>
		
		<input type="button" style="min-width:80px;" value="确定" onclick="AddProperty_Submit();" />
		<input type="button" style="min-width:80px;" value="取消" onclick="AddProperty_Cancel();" />
    }
</div>

这里注意的是最后的checkbox,它实际上是动态生成的,其个数不确定,但至少会有一个。为了和数据模型的绑定,参考上面的网址,其id采用数组的方式,名称和数据模型中的字段名称也保持一致,均为 toPrpGroup。

在action中的处理函数仅用于测试,代码如下:

[HttpPost]
public string AddProperty(PropertyAddViewModeo model)
{
	return CreateResultString(1, "组名称已经存在了,不允许重复");
}

不看处理代码,只看参数是否获取到了表单数据,当界面输入如下:

这里注意最后的两个选择框,acion的model参数内容如下所示:

获取的这些数据全都没错,现在不选“车牌相关”而只选中“司机相关”,则看获取到的数据如下:

这样就没有数据了,但是从表单中的确实获取到它的值了,看js中formData变量的值:"prpId=-1&prpDesc=aa&prpName=bb&prpValues=cc&prpDefValue=dd&toPrpGroup%5B1%5D=4&prpSubType=1"

这就有点麻烦了。对于数据模型的定义,我也参考上面的那个网址添加了构造函数并在其中对toPrpGroup进行了初始化new,通过多次尝试,这个初始化对结果没有任何影响,也就是说,是否有这个初始化,结果都是一样的。

从这里看,如果是从0开始选择,是可以正常获取到值的,但如果不是从0开始,就获取不到它的值,同样,我估计如果中间有没选中的,则后面的值也获取不到。

如果只是这个不能获取到值,就显然有点不爽,于是就把数据的名称改掉,如下所示:

<input type="checkbox" id="toPrpGroup" name="toPrpGroup" value="3">
<input type="checkbox" id="toPrpGroup" name="toPrpGroup" value="4">

这样改过之后,即名称不再使用数组的方式,结果就可以了,此时,如果两个都选中,则formData的值如下:

"prpId=-1&prpDesc=aa&prpName=bb&prpValues=cc&prpDefValue=dd&toPrpGroup=3&toPrpGroup=4&prpSubType=1"

有两个toPrpGroup参数,这样看,如果有多个值的,都可以采用这个方法,即数据模型采用 List 数据类型,form的字段名称不需要数组即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值