Generate JSON based on selected nested check-boxes

问题: I've dynamically created group of checkbox inputs based on JSON in nested way. Now I want to get all selected checkbox as an Array in parent-children form as given below:...

问题:

I've dynamically created group of checkbox inputs based on JSON in nested way. Now I want to get all selected checkbox as an Array in parent-children form as given below:

let data = {
  "personal-information": {
    "label": "personal-information",
    "children": {
      "first_name": {
        "type": "string",
        "label": "First Name",
        "optional": false
      },
      "last_name": {
        "type": "string",
        "label": "Last Name",
        "optional": false
      },
      "dob": {
        "type": "date",
        "label": "Date Of Birth",
        "optional": false
      },
      "gender": {
        "type": "string",
        "label": "Gender",
        "optional": false
      },
      "height": {
        "type": "string",
        "label": "Height",
        "optional": false
      },
      "weight": {
        "type": "string",
        "label": "Weight",
        "optional": false
      },
      "blood-group": {
        "type": "string",
        "label": "Blood-Group",
        "optional": false
      },
      "addresses": {
        "label": "addresses",
        "children": {
          "address-line-1": {
            "type": "string",
            "label": "Address",
            "optional": false
          },
          "address-line-2": {
            "type": "string",
            "label": "Address",
            "optional": false
          },
          "city": {
            "type": "string",
            "label": "City",
            "optional": false
          },
          "state": {
            "type": "string",
            "label": "State",
            "optional": false
          },
          "country": {
            "type": "string",
            "label": "Country",
            "optional": false
          },
          "zipcode": {
            "type": "string",
            "label": "Zip Code",
            "optional": false
          }
        }
      },
      "emergency-contact": {
        "label": "emergency-contact",
        "children": {
          "name": {
            "type": "string",
            "label": "Zip Code",
            "optional": false
          },
          "phone": {
            "type": "string",
            "label": "Phone",
            "optional": false
          },
          "email": {
            "type": "string",
            "label": "Email",
            "optional": false
          }
        }
      }
    }
  },
  "general-information": {
    "label": "general-information",
    "children": {
      "allergies": {
        "type": "String",
        "label": "Allergies",
        "optional": true
      },
      "habits": {
        "type": "String",
        "label": "Habits",
        "optional": true
      }
    }
  },
  "history": {
    "label": "history",
    "children": {
      "status": {
        "type": "Boolean",
        "label": "Status",
        "optional": false
      },
      "createdAt": {
        "type": "date",
        "label": "createdAt",
        "optional": false
      },
      "problem": {
        "type": "Text",
        "label": "Chief Complaint",
        "optional": true
      },
      "diagnosis": {
        "type": "Text",
        "label": "Diagnosis",
        "optional": true
      },
      "prescription": {
        "type": "Text",
        "label": "Prescription",
        "optional": true
      },
      "lab-result": {
        "label": "lab-result",
        "children": {
          "test-name": {
            "type": "string",
            "label": "Test Name",
            "optional": false
          },
          "loinc": {
            "type": "string",
            "label": "Loinc",
            "optional": false
          },
          "normal-range": {
            "type": "string",
            "label": "Normal Range",
            "optional": false
          },
          "unit": {
            "type": "string",
            "label": "Unit",
            "optional": false
          },
          "value": {
            "type": "string",
            "label": "Value",
            "optional": false
          },
          "test-result": {
            "type": "string",
            "label": "Test Name",
            "optional": false
          },
          "createdAt": {
            "type": "date-time",
            "label": "Time",
            "optional": false
          },
          "status": {
            "type": "Boolean",
            "label": "Status",
            "optional": false
          }
        }
      },
      "medication-history": {
        "label": "medication-history",
        "children": {
          "medication-name": {
            "type": "string",
            "label": "Medication Name",
            "optional": false
          },
          "notes": {
            "type": "string",
            "label": "Notes",
            "optional": false
          },
          "status": {
            "type": "Boolean",
            "label": "Status",
            "optional": false
          },
          "qty": {
            "type": "string",
            "label": "Quantity",
            "optional": false
          },
          "time-to-take": {
            "type": "string",
            "label": "No. of time to take",
            "optional": false
          },
          "createdAt": {
            "type": "date",
            "label": "Date",
            "optional": false
          }
        }
      }
    }
  }
};
let nodeLevel = 1;

function addItem(parentUL, branch, parentName) {
  for (var key in branch) {
    // console.log('Branch', branch[key]);
    // console.log('Key: ', key);
    var item = branch[key].children;
    // console.log('Item: ', item)

    let name = '';

    if (parentName) {
      name = parentName;
    }

    $item = $('<li>', {
      id: key
    });
    $item.append($('<input>', {
      type: "checkbox",
      id: key,
      name: key,
      value: key,
      "data-parent": name
    }));
    // $item.attr('data-parent', name);
    $item.append($('<label>', {
      for: key,
      text: key
    }));
    parentUL.append($item);
    nodeLevel++;
    if (branch[key].children) {
      var $ul = $('<ul>', {
        style: 'display: none'
      }).appendTo($item);

      addItem($ul, item, branch[key].label);
    } else {
      nodeLevel = 1;
    }
  }
}

$(function() {
  addItem($('#root'), data);
  $(':checkbox').change(function() {
    $(this).closest('li').children('ul').slideToggle();
  });

  // $('label').click(function() {
  //   $(this).closest('li').find(':checkbox').trigger('click');
  // });
});



$(".save").click(function() {

  var selected = new Array();

  var checkboxes = document.querySelectorAll('input[type=checkbox]:checked')

  let arrAll = {};
  for (var i = 0; i < checkboxes.length; i++) {
    let parent = checkboxes[i].getAttribute('data-parent');

    console.log('Checkbox: ', checkboxes[i]);
    console.log('Parent: ', parent);

    // let inputName = checkboxes[i].getAttribute('name');



    // console.log(inputName);

    // if(parent) {
    // 	arrAll[parent][inputName] = {};
    // } else {

    // 	arrAll[inputName] = {};	
    // }

    /*
    if(parent){
    	selected[parent] = [];
    	selected[parent].push(checkboxes[i].value);
    } else {
    	selected.push(checkboxes[i].value);
    } */
    // selected.push(checkboxes[i].value)
  }

  // console.log('Selected checkbox:', arrAll);

});
ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

ul ul {
  margin: 0 0 0 30px;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<ul id="root"></ul>

<button class="save">Save</button>

So if I select 1. personal-information -> first-name and last-name 2. personal-information -> addresses -> address-line-1 3. general-information -> allergies 4. history -> status

my expected output is:

{
  "personal-information":{
    "child":{
      "first_name":"first_name",
      "addresses":{
        "child":{
          "address1":"address1",
          "address2":"address2"
        }
      }
    }
  },
  "general-information":{
    "child":{
      "allergies":"allergies",
      "habits":"habits"
    }
  }
}

How can I do this with jQuery or Javascript?


回答1:

You could recursively walk over your data object again, like you did when creating the elements, to read the state. Instead of starting with an array of checkboxes, we start with the desired structure.

In this example I use the name attribute to match a UI element to the original data source. It would be better to store a reference to it sometime when creating it. This makes it easier to find the right element and does not make you rely on DOM queries.

Also note that your current HTML includes duplicate ids on the <li> and <checkbox> elements...

In short:

  • Loop over the entries of data
  • For each key, find a [name=${key}] element
  • If the element is checked, add its key to an object
  • If the value contains a children object, recurse.
  • If the value contains no children, add its value
const walkCheckedTree = (opts) => Object
    .entries(opts)
    .reduce((t, [k, v]) => {
      const cb = root.querySelector(`[name=${k}]`);

      if (cb.checked) {
        if (v.children) {
          t[k] = { child: walkCheckedTree(v.children) };
        } else {
          t[k] = k;
        }
      }

      return t;
    }, {});

const tree = walkCheckedTree(data);

Running example: (press save to log)

let data = {
  "personal-information": {
    "label": "personal-information",
    "children": {
      "first_name": {
        "type": "string",
        "label": "First Name",
        "optional": false
      },
      "last_name": {
        "type": "string",
        "label": "Last Name",
        "optional": false
      },
      "dob": {
        "type": "date",
        "label": "Date Of Birth",
        "optional": false
      },
      "gender": {
        "type": "string",
        "label": "Gender",
        "optional": false
      },
      "height": {
        "type": "string",
        "label": "Height",
        "optional": false
      },
      "weight": {
        "type": "string",
        "label": "Weight",
        "optional": false
      },
      "blood-group": {
        "type": "string",
        "label": "Blood-Group",
        "optional": false
      },
      "addresses": {
        "label": "addresses",
        "children": {
          "address-line-1": {
            "type": "string",
            "label": "Address",
            "optional": false
          },
          "address-line-2": {
            "type": "string",
            "label": "Address",
            "optional": false
          },
          "city": {
            "type": "string",
            "label": "City",
            "optional": false
          },
          "state": {
            "type": "string",
            "label": "State",
            "optional": false
          },
          "country": {
            "type": "string",
            "label": "Country",
            "optional": false
          },
          "zipcode": {
            "type": "string",
            "label": "Zip Code",
            "optional": false
          }
        }
      },
      "emergency-contact": {
        "label": "emergency-contact",
        "children": {
          "name": {
            "type": "string",
            "label": "Zip Code",
            "optional": false
          },
          "phone": {
            "type": "string",
            "label": "Phone",
            "optional": false
          },
          "email": {
            "type": "string",
            "label": "Email",
            "optional": false
          }
        }
      }
    }
  },
  "general-information": {
    "label": "general-information",
    "children": {
      "allergies": {
        "type": "String",
        "label": "Allergies",
        "optional": true
      },
      "habits": {
        "type": "String",
        "label": "Habits",
        "optional": true
      }
    }
  },
  "history": {
    "label": "history",
    "children": {
      "status": {
        "type": "Boolean",
        "label": "Status",
        "optional": false
      },
      "createdAt": {
        "type": "date",
        "label": "createdAt",
        "optional": false
      },
      "problem": {
        "type": "Text",
        "label": "Chief Complaint",
        "optional": true
      },
      "diagnosis": {
        "type": "Text",
        "label": "Diagnosis",
        "optional": true
      },
      "prescription": {
        "type": "Text",
        "label": "Prescription",
        "optional": true
      },
      "lab-result": {
        "label": "lab-result",
        "children": {
          "test-name": {
            "type": "string",
            "label": "Test Name",
            "optional": false
          },
          "loinc": {
            "type": "string",
            "label": "Loinc",
            "optional": false
          },
          "normal-range": {
            "type": "string",
            "label": "Normal Range",
            "optional": false
          },
          "unit": {
            "type": "string",
            "label": "Unit",
            "optional": false
          },
          "value": {
            "type": "string",
            "label": "Value",
            "optional": false
          },
          "test-result": {
            "type": "string",
            "label": "Test Name",
            "optional": false
          },
          "createdAt": {
            "type": "date-time",
            "label": "Time",
            "optional": false
          },
          "status": {
            "type": "Boolean",
            "label": "Status",
            "optional": false
          }
        }
      },
      "medication-history": {
        "label": "medication-history",
        "children": {
          "medication-name": {
            "type": "string",
            "label": "Medication Name",
            "optional": false
          },
          "notes": {
            "type": "string",
            "label": "Notes",
            "optional": false
          },
          "status": {
            "type": "Boolean",
            "label": "Status",
            "optional": false
          },
          "qty": {
            "type": "string",
            "label": "Quantity",
            "optional": false
          },
          "time-to-take": {
            "type": "string",
            "label": "No. of time to take",
            "optional": false
          },
          "createdAt": {
            "type": "date",
            "label": "Date",
            "optional": false
          }
        }
      }
    }
  }
};
let nodeLevel = 1;

function addItem(parentUL, branch, parentName) {
  for (var key in branch) {
    // console.log('Branch', branch[key]);
    // console.log('Key: ', key);
    var item = branch[key].children;
    // console.log('Item: ', item)

    let name = '';

    if (parentName) {
      name = parentName;
    }

    $item = $('<li>', {
      id: key
    });
    $item.append($('<input>', {
      type: "checkbox",
      id: key,
      name: key,
      value: key,
      "data-parent": name
    }));
    // $item.attr('data-parent', name);
    $item.append($('<label>', {
      for: key,
      text: key
    }));
    parentUL.append($item);
    nodeLevel++;
    if (branch[key].children) {
      var $ul = $('<ul>', {
        style: 'display: none'
      }).appendTo($item);

      addItem($ul, item, branch[key].label);
    } else {
      nodeLevel = 1;
    }
  }
}

$(function() {
  addItem($('#root'), data);
  $(':checkbox').change(function() {
    $(this).closest('li').children('ul').slideToggle();
  });

  // $('label').click(function() {
  //   $(this).closest('li').find(':checkbox').trigger('click');
  // });
});



$(".save").click(function() {
  const root = document.getElementById("root");
  
  const walkCheckedTree = (opts) => Object
    .entries(opts)
    .reduce((t, [k, v]) => {
      const cb = root.querySelector(`[name=${k}]`);

      if (cb.checked) {
        if (v.children) {
          t[k] = { child: walkCheckedTree(v.children) };
        } else {
          t[k] = k;
        }
      }
      
      return t;
    }, {});
  
  const tree = walkCheckedTree(data);
  
  console.log(tree);
});
ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

ul ul {
  margin: 0 0 0 30px;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<ul id="root"></ul>

<button class="save">Save</button>

  • 发表于 2018-07-05 20:18
  • 阅读 ( 293 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除