繁体   English   中英

Javascript将表格序列化为JSON

[英]Javascript serialize form as JSON

我使用以下函数将表单序列化为json对象。

   $.fn.serializeObject = function()
    {
        var o = {};
        var a = this.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 || '';
            }
        });
        return o;
    };

它返回我的结果如下:

{
"address": "aaaa",
"organization": "66",
"region": "44",
"nodeType": "HANGING",
"description": "asdasdasdasd",
"longitude": "45.8888",
"latitude": "45.8888"
}

但是我需要一个不同的结果。 我需要将选择选项作为包含id值的对象发送。 我该如何使用javascript函数执行此操作?

{
    "address": "",
    "description": "aaa",
    "nodeType": {
        "idNodeType": "WELL"
    },
    "region": {
        "idRegion": "56"
    },
    "organization": {
        "idOrganization": "66"
    },
    "location": {
        "latitude": "46.234234",
        "longitude": "45.23423"
    }
}

我可以通过几种方法来实现这一目标。 我将向您展示一些结合了三个代码的代码,以便您选择喜欢的代码。 在所有情况下,在您的serializeObject方法中应用该值之前,我们都会在对象内创建路径。 为此,我添加了一个将执行此操作的递归私有方法。 解决了这一问题后,唯一的问题就是如何确定实现价值的最终途径,这就是我找到三种不同方式的地方:

  1. 输入具有所需路径的输入名称,如:

     <input name="some.path" /> 
  2. 在对象中使用属性来形成路径。 我在示例中使用了data- *属性,但您可以轻松更改为使用id。 例如,这将导致JSON对象中region-> idRegion的映射:

     <select name="region" data-form-path="idRegion"> 
  3. 创建一个映射对象,以确定如何将输入名称映射到对象路径,例如:

     var mapping = { "country" : "location.country", "isForeignCountry" : "location.isForeignCountry" } 

因此,这是一个示例表单,我们可以用来演示其工作方式:

     <form>
        <input type="text" name="name" value="1"/>
        <input type="text" name="lasntame" value="2"/>
        <input type="text" name="photos.total" value="2"/>
        <input type="text" name="photo.items" value="face.jpg" id="b"/>
        <input type="text" name="photo.items" value="landscape.jpg" id="b"/>            
        <textarea name="userData.comments" data-form-path="1355998"></textarea>
        <select name="region" data-form-path="idRegion">
            <option value="5" selected="selected">5</option>
            <option value="6">6</option>
            <option value="7">7</option>
        </select>
        <select name="country" >
            <option value="5" selected="selected">5</option>
            <option value="6">6</option>
            <option value="7">7</option>
        </select>
        <input type="checkbox" checked="checked" name="isForeignCountry" value="8" id="f">
        <input type="submit" name="check" value="Submit" id="g">
    </form>

如您所见,我们有名为“ photos.total”和“ photos.items”的输入。 有两个“项目”,因此您可以看到多个值字段仍然可以正确转换。 它们使用第一种方法映射到最终值路径。

我们还有两个项目具有data-form-path属性(顺便说一句,是HTML5有效data- *属性)。 这些将使用第二种方法,对于积分,textarea名称中具有路径,因此也使用第一种方法。

修改后的代码将发挥作用,如下所示:

    $.fn.serializeObject = function(mapping)
    {
            var o = {};
            var a = this.serializeArray();
            var that = this;
            $.each(a, function() {
                var name = this.name;
                // We store current reference in a variable because when a nested path 
                // is created, the value is set on the last element of the path, 
                // instead of the JSON root 
                var currentRef = o;

                if(!mapping) {
                  // 1st way: using names with path, like 'inputname="location.latitude" '
                  if(name.indexOf('.') != -1) {
                    var path = name.split('.');
                    currentRef = createPath(o, path);
                    name = name.split('.').splice(-1,1);
                  }

                  // Second way: adding metadata (this could be simply the id instead)
                  // Bonus! supports also paths with dots
                  var idData = $("*[name='" + this.name + "']",that).data("form-path");
                  if(idData){
                    currentRef = createPath(currentRef, [name,idData]);
                    name = idData;
                  }
                }
                else {
                  // Final way: simply use a mapping between form inputs and json path
                  if(mapping[name]){                
                    var path = mapping[name].split('.');
                    currentRef = createPath(o, path);                
                    name = name.split('.').splice(-1,1);
                  }
                }

                if (currentRef[name] !== undefined) {
                    if (!currentRef[name].push) {
                        currentRef[name] = [currentRef[name]];
                    }
                    currentRef[name].push(this.value || '');
                } else {
                    currentRef[name] = this.value || '';
                }
            });

            // Recursively create a path in the obj item and return
            // the last created object reference
            function createPath(obj, pathArray) {
                var item = pathArray.splice(0,1);
                var returnObj;

                if(pathArray.length === 0) {
                    returnObj = obj;
                }
                else if(!obj[item]) {
                    obj[item] = {};
                    returnObj = createPath(obj[item], pathArray);
                }
                else returnObj = createPath(obj[item], pathArray);

                return returnObj;
            }

            return o;
    };

现在,如果我们在没有映射的情况下进行呼叫,则此表单的结果为:

    {
        "name":"1",
        "lasntame":"2",
        "photo":{
            "total":"2",
            "items":[
                "face.jpg",
                "landscape.jpg"]
        }
        ,"userData":{
            "comments":{
                "1355998":""
            }
        },
        "region":{
            "idRegion":"5"
        },
        "country":"5",
        "isForeignCountry":"8"
    }

名称为“ photos。*”的输入已放入与名称对应的路径中。 并且具有data-form-path属性的输入也正确缩进了。

如果不能修改HTML(让我说您在询问时需要更加具体!),则可以使用输入映射对象。 因此,如果我这样打电话:

    var mapping = {
        "country" : "location.country",
        "isForeignCountry" : "location.isForeignCountry"
    }
    console.log( $("form").serializeObject(mapping) );

使用对象映射代替其他规则,结果是:

    {
        "name":"1",
        "lasntame":"2",
        "photo.total":"2",
        "photo.items":[
            "face.jpg",
            "landscape.jpg"],
        "userData.comments":"",
        "region":"5",
        "location":{
            "country":"5",
            "isForeignCountry":"8"
        }
    }

我想这应该可以满足您的需求。 希望您有更多详细信息,例如显示HTML并说明可以更改或不能更改的内容。 让我知道这是否对您有帮助。 干杯!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM