【问题标题】:Javascript serialize form as JSONJavascript 将表单序列化为 JSON
【发布时间】:2017-02-18 13:02:36
【问题描述】:

我使用以下函数将我的表单序列化为 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"
    }
}

【问题讨论】:

    标签: javascript jquery json serialization


    【解决方案1】:

    我可以想出几种方法来实现这一点。我将向您展示一些结合了三个的代码,以便您选择您喜欢的一个。 在所有情况下,我们都是在将值应用于您的 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 并解释你可以改变什么或不能改变什么。让我知道这是否对您有帮助。干杯!

    【讨论】:

    • 没完没了的 tnaks 供您注意!你的回答真的很棒而且很有帮助! ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-10
    • 2012-02-25
    • 2021-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多