【问题标题】:Get value of JSON object with inner objects by HTML form field name without eval通过不带 eval 的 HTML 表单字段名称获取带有内部对象的 JSON 对象的值
【发布时间】:2011-05-13 21:43:16
【问题描述】:

我有一个类似Convert an HTML form field to a JSON object with inner objects 的问题,但在另一个方向。

这是来自服务器的 JSON 对象响应:

{
    company : "ACME, INC.",
    contact : {
        firstname : "Daffy", 
        lastname : "Duck"
    }
}

这是 HTML 表单:

<form id="myform">
    Company: <input type="text" name="company" />
    First Name: <input type="text" name="contact.firstname" />
    Last Name: <input type="text" name="contact.lastname" />
</form>

这是(伪)代码:

var aFormFields; 

for (var i = 0, iMax = aFormFields.length; i < iMax; i++) {

    var sFieldName = aFormFields[i].getAttribute('name');
    eval("sFieldValue = oResponse."+sFieldName);

}

好的,我的解决方案有效,但我正在寻找一种从代码中删除邪恶 eval 的好方法。 该解决方案还应该适用于字段名称中包含任意点数的表单字段。

【问题讨论】:

  • 你的直觉是正确的:如果你认为你需要使用eval(),那么你可能需要学习一些新的东西 :-) 继续嗅探你的代码!
  • 我不太确定:您是要从 AJAX 服务器响应中填充输入字段,还是要从输入字段的内容中生成服务器响应?
  • 在一个不相关的说明中:来自服务器的响应不是有效的 JSON。

标签: javascript json object eval forms


【解决方案1】:

代替:

eval("sFieldValue = oResponse."+sFieldName); 

用于单点字段:

sFieldValue = oResponse[sFieldName];

这将通过其键检索值。

现在,如果您需要更多,您需要执行以下操作:

  1. . 上拆分sFieldName
  2. 循环遍历该数组并向下输入oResponse,直到达到所需的值

代码可能如下所示:

var node = oResponse, parts = sFieldName.split('.');
while(parts.length > 0) {
   node = node[parts.shift()];
}
// node will now have the desired value

更多关于“会员运营商”的信息:
https://developer.mozilla.org/en/JavaScript/Reference/Operators/Member_Operators

【讨论】:

  • 是的,这行得通:sFieldValue = oResponse['company'];但这不是 sFieldValue = oResponse['contact.firstname']
  • 抱歉,没有发现我的道歉,我已经更新了我的答案:)
【解决方案2】:

这适用于单个属性:

sFieldValue = oResponse[sFieldName]

但它不适用于像contact.firstname 这样的嵌套数据。 为此,用点分割名称,并使用循环遍历每个名​​称:

var aFormFields; 

for (var i = 0, iMax = aFormFields.length; i < iMax; i++) {

    var aFieldNameParts = aFormFields[i].getAttribute('name').split(".");
    var oFieldValue = oResponse;
    for(var j=0; j<aFieldNameParts.length; j++) {
        oFieldValue = oFieldValue[aFieldNameParts[j]];
    }
    var sFieldValue = oFieldValue;
}

注意:如果某个属性不存在,则会发生错误。您可能想检查oFieldValue[ aFieldNameParts[j] ] 是否存在。

【讨论】:

  • 谢谢,你成就了我的一天!这是我一直在寻找的正确解决方案
【解决方案3】:

虽然有可能,但我不会遍历输入字段,而是遍历 JSON 对象:

function fillForm (form, data, prefix) {
  prefix = prefix ? prefix + "." : "";
  for (var x in data) {
    if (typeof data[x] === "string") {
      var input = form.elements[prefix + x];
      if (input)
        input.value = data[x];
    } else
      fillForm(form, data[x], prefix + x);
  }
}

fillForm(document.getElementById("myform"), oResponse);

(未经测试)

【讨论】:

  • 这是一个好主意,但在我的情况下不是,因为我在 json 对象中有更多元素,即 html 形式的字段。所以我更喜欢遍历表单字段
【解决方案4】:

假设您的命名方案是一致的,您可以将点表示法转换为下标。您必须在句点上拆分字段名称并迭代或递归标记,将每个标记转换为下标。当然,这假设oResponse 始终包含每个字段的值。

for (var i = 0; i < aFormFields.length; i++) {
    var sFieldName = aFormFields[i].getAttribute('name');
    var tokens = sFieldName.split('.');
    var cur = oResponse;

    for (var j = 0; j < tokens.length; j++) {
        cur = cur[tokens[j]];
    }

    sFieldValue = cur;
}

【讨论】:

    【解决方案5】:

    请将此视为答案和问题的组合:)

    我目前正试图让我的服务器对我从像你一样的表单发送的数据进行 jsonify...

    在我的情况下,表单最终将创建一个带有多个子对象的 json 对象,这些子对象可以具有子对象,这些子对象也可以具有...。

    深度由用户决定,所以我应该能够支持无限递归。

    到目前为止,我的“解决方案”感觉不对,但它正确地完成了工作, 函数 getRequestBody 从 expressjs 获取一个 req.body 对象, 这基本上是一个具有以下映射的对象:

    {
      "ridic-ulously-deep-subobject": "value",
      "ridic-ulously-deep-subobject2": "value",
      "ridic-ulously-deep2-subobject3": "value",
    }
    

    以下 html 正在使用中:

    <form>
        <input name="ridic-ulously-long-class-string" value="my value" />
      </form>
    

    和 javascript 函数(应该可以正常工作,像上面一样为它提供一个 req.body 对象,它会返回一个 json 对象):

    function getRequestBody(reqB){
    
      var reqBody = {};
    
      for(var keys in reqB) {
    
        var keyArr = keys.split('-');
    
        switch(keyArr.length){
          case 1:
            if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
            reqBody[keyArr[0]] = reqB[keys];
          break;
    
          case 2:
            if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
            if(!reqBody[keyArr[0]][keyArr[1]]) reqBody[keyArr[0]][keyArr[1]] = {};
    
            reqBody[keyArr[0]][keyArr[1]] = reqB[keys];
          break;
    
          case 3:
            if(!reqBody[keyArr[0]]) reqBody[keyArr[0]] = {};
            if(!reqBody[keyArr[0]][keyArr[1]]) reqBody[keyArr[0]][keyArr[1]] = {};
            if(!reqBody[keyArr[0]][keyArr[1]][keyArr[2]]) reqBody[keyArr[0]][keyArr[1]][keyArr[2]] = {};
    
            reqBody[keyArr[0]][keyArr[1]][keyArr[2]] = reqB[keys];
          break;
    
          case 4:
    
          // ...
          //and so on, always one line longer
      }
    
        return reqBody;
    }
    

    这感觉不对,它现在只覆盖 5 个级别的子对象, 不过,可能会发生应用程序具有足够的功能来达到七个甚至十个级别的情况。

    应该是一个常见问题,但我的搜索努力在 10 分钟内没有任何结果, 这通常意味着我缺少一些关键字 要么 [还] 没有可行的解决方案(在这种情况下我真的无法想象)。

    有没有人有足够的想象力和逻辑来解决这个问题,还是我只需要扩展这个功能,让我变得更加混乱,让我降到 10 个可能的子级别?

    我认为最终它不会对性能产生很大影响, 但我真的不想创造这个可怕的庞然大物:D

    玩得开心

    贾沙

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-09
      • 2011-10-28
      • 2012-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多