1

I am using jQuery to write out nested lists as JSON.

I'm running into issues surrounding the nested elements. I created a Plunk that you can use to recreate the issue with the simple click of a button.

Plunk: https://plnkr.co/edit/jLi9epblNAtMbzezcRSY?p=preview

HTML:

<h1>Hello Plunker!</h1>
<div class="dd" name="agenda-nestable" id="nestable">
    <ol id="agenda-root" class="dd-list">
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Pledge of Allegiance</div>
            </li>
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Roll Call</div>
                    <ol class="dd-list">
                            <li class="dd-item" data-id="0">
                            <div class="dd-handle">Establish a Quorum</div></li>
                    </ol>
            </li>
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Public Comment</div>
                    <ol class="dd-list">
                            <li class="dd-item" data-id="0">
                            <div class="dd-handle">Address</div></li>
                            <li class="dd-item" data-id="0">
                            <div class="dd-handle">Open Floor</div></li>
                    </ol>
            </li>
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Action to set agenda and to approve consent agenda items</div>
            </li>
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Presentations and awards</div>
            </li>
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Matters set for a specific time</div>
            </li>
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Regular Agenda</div>
            </li>
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Governing Board</div>
            </li>
            <li class="dd-item" data-id="0" id="0">
                <div class="dd-handle">Closed Session</div>
            </li>
    </ol>
</div>
<pre id="jsonOutput"></pre>
<button value onclick='convertToJson()'>Convert nodes to JSON</button>

Code:

function convertToJson() {
  var sectionOrder = "";
  var itemOrder = "";
  var sectionDelimiter = "";
  var itemDelimiter = "";

  var agendaDiv = $("[name='agenda-nestable']");
  var agendaSections = $(agendaDiv).find("ol#agenda-root>li");
  var sections = [];

  for (var i = 0; i < agendaSections.length; i++) {
      var agendaSection = agendaSections[i];
      var section = {};
      section.Id = $(agendaSection).attr('data-id');
      section.SectionText = $(agendaSection).find("div:first-child").text(); // Something wrong here
      section.Items = [];

      var sectionItems = $(section).find("ol>li");
      for (var j = 0; j < sectionItems.length; j++) {
          var sectionItem = sectionItems[j];
          var item = {};
          item.Id = $(sectionItem).attr('data-id');
          item.ItemText = $(sectionItem).find("div:first-child").text(); // Something wrong here
          section.Items.push(item);
      }
      sections.push(section);
  }
  var json = JSON.stringify(sections, null, 2);;
  $('#jsonOutput').text(json);
  console.log(json);
  return json;
}

Output:

  {
    "Id": "0",
    "SectionText": "Pledge of Allegiance",
    "Items": []
  },
  {
    "Id": "0",
    "SectionText": "Roll CallEstablish a Quorum", // THIS IS WRONG, should be in Items Array, not munged together
    "Items": []
  },
  {
    "Id": "0",
    "SectionText": "Public CommentAddressOpen Floor", // THIS IS WRONG, should be in Items Array, not munged together
    "Items": []
  },
  {
    "Id": "0",
    "SectionText": "Action to set agenda and to approve consent agenda items",
    "Items": []
  },
  {
    "Id": "0",
    "SectionText": "Presentations and awards",
    "Items": []
  },
  {
    "Id": "0",
    "SectionText": "Matters set for a specific time",
    "Items": []
  },
  {
    "Id": "0",
    "SectionText": "Regular Agenda",
    "Items": []
  },
  {
    "Id": "0",
    "SectionText": "Governing Board",
    "Items": []
  },
  {
    "Id": "0",
    "SectionText": "Closed Session",
    "Items": []
  }
]

Thank you very much for taking a look, I really appreciate it!!!

Philip

Philip Tenn
  • 6,003
  • 8
  • 48
  • 85
  • "I'm running into issues". What are the issues? The code in the link doesn't seem to be the same as in the question – ADyson Jun 29 '17 at 22:12

3 Answers3

1

var section = {};

var sectionItems = $(section).find("ol>li");

This is your problem. You trying to use object as jquery element.

Use $(agendaSection) instead.

Also your li elements have the same id that is not allowed.

$(document).ready(function () {

  function convertToJson() {

    var nestable = $("#nestable"),
      root = $('#agenda-root'),
      agendaSections = $("#agenda-root>li"),
      sections = [];
    
    agendaSections.each(function() {
      var section = {};
      section.Id = $(this).attr('data-id');
      section.SectionText = $(this).find(".dd-handle").first().text(); // Something wrong here
      section.Items = [];
      
      $(this).find('.dd-list').find('.dd-item').each(function() {
        var item = {};
        item.Id = $(this).attr('data-id');
        item.ItemText = $(this).find(".dd-handle").first().text(); // Something wrong here
        section.Items.push(item);
      })
      sections.push(section);
    });
    
    var json = JSON.stringify(sections, null, 2);
    $('#jsonOutput').text(json);
    console.log(json);
    return json;
  }

  $('#toJson').click(convertToJson);

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="dd" name="agenda-nestable" id="nestable">
    <ol id="agenda-root" class="dd-list">
      <li class="dd-item" data-id="1" id="1">
        <div class="dd-handle">Pledge of Allegiance</div>
      </li>
      <li class="dd-item" data-id="2" id="2">
        <div class="dd-handle">Roll Call</div>
        <ol class="dd-list">
          <li class="dd-item" data-id="1">
            <div class="dd-handle">Establish a Quorum</div>
          </li>
        </ol>
      </li>
      <li class="dd-item" data-id="3" id="3">
        <div class="dd-handle">Public Comment</div>
        <ol class="dd-list">
          <li class="dd-item" data-id="1">
            <div class="dd-handle">Address</div>
          </li>
          <li class="dd-item" data-id="2">
            <div class="dd-handle">Open Floor</div>
          </li>
        </ol>
      </li>
      <li class="dd-item" data-id="4" id="4">
        <div class="dd-handle">Action to set agenda and to approve consent agenda items</div>
      </li>
      <li class="dd-item" data-id="5" id="5">
        <div class="dd-handle">Presentations and awards</div>
      </li>
      <li class="dd-item" data-id="6" id="6">
        <div class="dd-handle">Matters set for a specific time</div>
      </li>
      <li class="dd-item" data-id="7" id="7">
        <div class="dd-handle">Regular Agenda</div>
      </li>
      <li class="dd-item" data-id="8" id="8">
        <div class="dd-handle">Governing Board</div>
      </li>
      <li class="dd-item" data-id="9" id="9">
        <div class="dd-handle">Closed Session</div>
      </li>
    </ol>
  </div>

  <pre id="jsonOutput"></pre>
  <button type="button" id="toJson">Convert nodes to JSON</button>

This is how it works.

Timur Gilauri
  • 824
  • 8
  • 13
1

There are two issues in your JS.

Issue: 1

find("div:first-child") will match all the div:first-child, thats why the text of the div under ol > li is also captured. So change the line

from

 $(agendaSection).find("div:first-child").text();

to

$(agendaSection).find("> div:first-child").text();

Issue: 2

You need to pass agendaSection when finding the ol, not section, which is a variable that holds an object.

var sectionItems = $(agendaSection).find("ol>li");
karthick
  • 11,998
  • 6
  • 56
  • 88
1

Issue 1: Text is munged together:

JQuery .text() returns the text content of ALL the child nodes under your source node. That's why you get "Public CommentAddressOpen Floor". http://api.jquery.com/text/

See this answer for some ways to avoid this issue: jQuery: exclude children from .text(). The definitive way to avoid this issue is detailed here: http://viralpatel.net/blogs/jquery-get-text-element-without-child-element/.

Issue 2: Why no Items?

Once that's fixed, you still don't have subitems. Here's a good tip: When your output is not what you expect, check your input. In this case, your selector is wrong. You're selecting from your output array, instead of your list of jQuery sections. In other words, this:

$(section).find("ol>li");

should be this:

agendaSection.find("ol>li");

Here's a pen that works:

https://codepen.io/anon/pen/awqwEV

In the pen, I also took the liberty of prefixing the jQuery variables with $ and doing that jQuery assignment at variable assignment. So, agendaSection is now $agendaSection, and jQuery only does the work of wrapping that element once. These are good practices that should help you in the long run.

xweb
  • 123
  • 1
  • 1
  • 8