Преобразовать сплюснутый JSON для форм обратно в объект - PullRequest
0 голосов
/ 20 апреля 2010

Мне нужно требуется (поэтому, пожалуйста, не придирчиво к требованию, я его уже выбрал, и это требование) для преобразования определенных полей формы, в которые встроено "вложение объектов" имена полей, обратно к самим объектам. Ниже приведены некоторые типичные имена полей формы:

  • phones_0_patientPhoneTypeId
  • phones_0_phone
  • phones_1_patientPhoneTypeId
  • phones_1_phone

Поля формы выше были получены от объекта, подобного тому, который расположен внизу (см. «Данные»), и это формат объекта, который мне нужно собрать. Можно предположить, что любое поле формы с именем, которое содержит символ подчеркивания _, должно пройти это преобразование. Кроме того, что сегмент поля формы между подчеркиваниями, если он числовой, означает массив Javascript, в противном случае - объект.

Мне было легко придумать (несколько наивную) реализацию для "сплющивания" исходного объекта для использования формой, но я изо всех сил пытаюсь идти в другом направлении; ниже объекта / данных ниже я вставляю свою текущую попытку. Одна проблема (возможно, единственная?) Заключается в том, что в настоящее время он неправильно учитывает индексы массивов, но это может быть непросто, поскольку впоследствии объект будет закодирован как JSON, который не будет учитывать разреженные массивы. Так что, если "phones_1" существует, а "phones_0" нет, я тем не менее хотел бы убедиться, что слот для телефонов [0] существует, даже если это значение равно нулю.

Реализации, которые меняют то, что я начал, или совершенно другие, поощряются. Если интересно, дайте мне знать, хотите ли вы увидеть мой код для работающей "уплощающей" части. Заранее спасибо

Данные:

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];
                }
            }
        }

Ответы [ 3 ]

1 голос
/ 21 апреля 2010

Я бы изменил имена полей формы, чтобы было немного проще понять, что такое массив и что такое объект, использующий эту структуру:

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]. Также последний элемент должен быть свойством объекта вместо элемента массива, то есть вы не можете делать 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');
0 голосов
/ 21 апреля 2010

Спасибо за другие ответы. Вот как я подправил код, который у меня уже был, я знал, что был близок.

    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];
                }
            }
        }
    }
0 голосов
/ 21 апреля 2010

Для каждого поля формы:

Например. phones_0_patientPhoneTypeId

  1. Разделите имя на _, чтобы получить массив: ["phones","0","patientPhoneTypeId"]
  2. reverse() этот массив: ["patientPhoneTypeId","0","phones"]
  3. Поместите объект шаблона в переменную, я буду использовать o
  4. pop() массив, пока он не станет пустым, и для каждой вещи, кроме последней, выполните o = o[resultOfPop]
  5. Для последнего, просто установите значение, например o[resultOfPop] = valueFromField

Если вы не хотите / не хотите использовать объект шаблона, вам нужно добавить пустой объект или массив на шаге 4.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...