我必需(因此请不要挑选这个要求,我已经挑选了它,这就是req)来转换某些嵌入了“对象嵌套”的表单字段在字段名称中,返回对象本身。以下是一些典型的表单字段名称:
上面的表单字段来自一个对象,例如向下的对象(参见“数据”),这是我需要重新组装的对象的格式。可以假设任何名称包含下划线_字符的表单字段都需要进行此转换。下划线之间的表单字段的段(如果是数字)表示Javascript数组,否则表示对象。
我发现很容易设计一个(有点幼稚)实现原始对象的“扁平化”以供表单使用,但我正朝着另一个方向奋斗;在下面的对象/数据下方,我正在粘贴当前的尝试。一个问题(也许是唯一一个?)是它目前没有正确考虑数组索引,但这可能很棘手,因为该对象随后将被编码为JSON,这将不考虑稀疏数组。因此,如果“phones_1”存在,但“phones_0”不存在,我仍然希望确保电话[0]存在一个插槽,即使该值为空。
鼓励调整我已经开始或完全不同的实现。如果有兴趣,请告诉我您是否希望看到我的代码“flattening”部分正在运行。提前致谢
数据:
var obj = {
phones: [{
"patientPhoneTypeId": 4,
"phone": "8005551212"
},
{
"patientPhoneTypeId": 2,
"phone": "8885551212"
}]};
迄今为止的代码:
var unflattened = {};
for (var prop in values) {
if (prop.indexOf('_') > -1) {
var lastUnderbarPos = prop.lastIndexOf('_');
var nestedProp = prop.substr(lastUnderbarPos + 1);
var nesting = prop.substr(0, lastUnderbarPos).split("_");
var nestedRef, isArray, isObject;
for (var i=0, n=nesting.length; i<n; i++) {
if (i===0) {
nestedRef = unflattened;
}
if (i < (n-1)) { // not last
if (/^\d+$/.test(nesting[i+1])) {
isArray = true;
isObject = false;
}
else {
isArray = true;
isObject = false;
}
var currProp = nesting[i];
if (!nestedRef[currProp]) {
if (isArray) {
nestedRef[currProp] = [];
}
else if (isObject) {
nestedRef[currProp] = {};
}
}
nestedRef = nestedRef[currProp];
}
else {
nestedRef[nestedProp] = values[prop];
}
}
}
答案 0 :(得分:1)
我会将表单字段名称更改为暗示什么是数组更简单,以及使用此结构的对象是什么:
property.<remaining> => looking at "property" object
property[i].<remaining> => looking at "property" array with index "i"
使用此信息,在没有太多字符串和索引操作的情况下重新生成数组变得更容易。假设我们有一个空的根对象,你可以为它添加一个名为set
的方法,它只是按原样获取属性字符串,并构建对象,无论它有多深的嵌套。
var object = {};
object.set = function(key, value) {
var parts = key.split(".");
var current = this; // begin at root
var arrayRegex = /(\w+)\[(\d+)\]/, nameAndIndex, name, index;
while(parts.length) {
part = parts.shift();
nameAndIndex = part.match(arrayRegex);
// property is an array
if(nameAndIndex != null) {
name = nameAndIndex[1];
index = nameAndIndex[2];
current[name] = current[name] || [];
current[name][index] = current[name][index] || {};
current = current[name][index];
}
// property is an object
else {
current[part] = current[part] || {};
current = current[part]; // edit: was missing this line before
}
}
current[part] = value;
};
这可以处理深层嵌套的结构,但有一点需要注意,你必须在每个级别都有一个对象。例如,您无法执行someProperty[1][2]
,但可以执行someProperty[1].anotherProperty[2]
。此外, last 项必须是对象属性而不是数组元素,这意味着您无法执行x.y.z.lastProperty[1]
,但您可以执行x.y.z.anArray[1].lastProperty
。如果上述情况不起作用,则可以更改set
方法并添加其他检查。
使用以下测试用例在http://jsfiddle.net/ysQpF/上创建了一个示例:
object.set('phones[0].phoneType', 1);
object.set('phones[0].phone', '312-223-4929');
object.set('phones[0].details[0].areaCode', '312');
object.set('phones[0].details[0].region[0].name', 'Alaska');
object.set('phones[0].details[0].region[1].name', 'California');
object.set('phones[1].phoneType', 2);
object.set('phones[1].phone', '408-332-3011');
答案 1 :(得分:0)
对于每个表单字段:
EG。 phones_0_patientPhoneTypeId
["phones","0","patientPhoneTypeId"]
reverse()
数组:["patientPhoneTypeId","0","phones"]
o
pop()
数组,直到它为空,除了最后一个之外的每一个都做o = o[resultOfPop]
o[resultOfPop] = valueFromField
如果您没有/想要使用模板对象,则需要在步骤4中添加空对象或数组。
答案 2 :(得分:0)
感谢其他答案。这是我如何调整我已经拥有的代码,我知道我已经接近了。
var unflattened = {};
for (var prop in values) {
if (prop.indexOf('_') > -1) {
var nesting = prop.split("_");
var nestedProp = nesting.pop();
if (!nesting.length || !nestedProp) {
console.log("form field name: '" + origProp + "' cannot be converted to 'nested' object");
continue;
}
var nestedRef, currProp, isArray, isObject;
for (var i=0, n=nesting.length; i<n; i++) {
if (i === n-1) { //last
isArray = /^\d+$/.test(nestedProp);
}
else {
isArray = /^\d+$/.test(nesting[i+1]);
}
isObject = !isArray;
currProp = nesting[i];
if (i===0) {
nestedRef = unflattened;
}
if (!nestedRef[currProp]) {
if (isArray) {
nestedRef[currProp] = [];
}
else {
nestedRef[currProp] = {};
}
}
nestedRef = nestedRef[currProp];
if (i === n-1) { //last
nestedRef[nestedProp] = values[prop];
}
}
}
}