Generating a json object from given data

162
January 20, 2020, at 2:00 PM

I'm having difficulty generating a json object in the below format from the data below. Fiddle

[ { Invoice: 
    { 
       headers: { date: "15-01-2020", buyer: "McDonalds", order: "145632"}, 
       items: { name: "Big Mac",   quantity: "5",  rate: "20.00"}, 
       items: { name: "Small Mac", quantity: "10", rate: "10.00"} 
    } 
  } 
, { Invoice: { // Other invoices go here, I've used just one for this example} } 
] 
<div class="invoice">
  <div class="header">
    <div contenteditable data="date">15-Jan-2020</div>
    <div contenteditable  data="buyer">McDonalds</div>
    <div contenteditable  data="order">145632</div>
  </div>
  <div class="item">
    <div contenteditable data="name">Big Mac</div>
    <div contenteditable data="quantity">5</div>
    <div contenteditable data="rate">20.00</div>
  </div>
  <div class="item">
    <div contenteditable data="name">Small Mac</div>
    <div contenteditable data="quantity">10</div>
    <div contenteditable data="rate">10.00</div>
  </div>
</div>
<button>Loop</button>

jQuery

var button = $("button")
button.on("click",function() {  
  jsonObj =[];
  $('.invoice>.header>div, .invoice>.item>div').each(function(index,item) {
    console.log($(this).parent().attr('class'));
    console.log($(this).attr('data'),$(this).text());
    q = {}
    q ['header'] = $(this).parent().attr('class');
    q [$(this).attr('data')] = $(this).text();
    jsonObj.push(q);
   });
   console.log(jsonObj);
   console.log(JSON.stringify(jsonObj));
});

I current end up with an object like this where the keys are repeated everywhere. How can I get this right?

  [ { "header": "header", "date": "15-Jan-2020"} 
  , { "header": "header", "buyer": "McDonalds"} 
  , { "header": "header", "order": "145632"} 
  , { "header": "item", "name": "Big Mac"} 
  , { "header": "item", "quantity": "5"} 
  , { "header": "item", "rate": "20.00"} 
  , { "header": "item", "name": "Small Mac"} 
  , { "header": "item", "quantity": "10"} 
  , { "header": "item", "rate": "10.00"} 
  ] 
Answer 1

In your example, you have an object with two same keys:

"items":{
    "name":"Big Mac",
    "quantity":"5",
    "rate":"20.00"
}
"items":{
    "name":"Small Mac",
    "quantity":"10",
    "rate":"10.00"
}

This won't work, because you can only have one, so you need to change the value of items key to an array of objects:

"items":[
    {
        "name":"Big Mac",
        "quantity":"5",
        "rate":"20.00"
    },
    {
        "name":"Small Mac",
        "quantity":"10",
        "rate":"10.00"
    }
]

The iteration code may look like this:

const jsonObj = [];
$('.invoice').each((index, item) => {
 const invoice = {
    header: {},
    items: []
 };
 $(item).find('.header > div').each((index, item) => {
    const key = $(item).attr('data');
    invoice.header[key] = $(item).text();
 });
 $(item).find('.item').each((index, item) => {
    const itemObj = {};
    $(item).find('div').each((index, item) => {
        const key = $(item).attr('data');
        itemObj[key] = $(item).text();
    });
    invoice.items.push(itemObj);
 });
 jsonObj.push({
    Invoice: invoice
 });
});

The main difference from your version is that it iterates through the dom step by step. First, through each invoice, then through each header of the invoice and each item. This way it's easy to build the desired structure.

Here's the jsfiddle link: https://jsfiddle.net/tara5/tanb174h/

Answer 2

Pure JS code for this:

Remarks : I have changed:
<div ... data="..."> ... </div>
to
<div ... data-ref="..."> ... </div>

to be conform with HTML directives (see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-* )

const jsonObj  = [] 
  ,   inVoices = document.querySelector('.invoice') 
  ,   subDivOf = (parent,query) => [...parent.querySelectorAll(query)] 
  ,   dataElms = (ac,el)=>{ac[el.dataset.ref]=el.textContent;return ac } 
  ; 
 
Loop.onclick=_=> 
  { 
  jsonObj.push( { Invoice: getInVoicesValues() } ) 
  console.clear() 
  console.log( jsonObj ) 
  } 
function getInVoicesValues()  
  { 
  const headers  = subDivOf(inVoices,'.header>div').reduce(dataElms,{}) 
    ,   items    = subDivOf(inVoices,'.item').reduce((accI,itm)=> 
                      { 
                      accI.push( subDivOf(itm, 'div').reduce(dataElms,{})) 
                      return accI 
                      },[]) 
      ; 
  return { headers, items }       
  }
.as-console-wrapper { 
    max-height: 100% !important; 
    width: 50% !important; 
    top: 0; 
    left: 50% !important; 
  }
<div class="invoice"> 
  <div class="header"> 
    <div contenteditable data-ref="date">15-Jan-2020</div> 
    <div contenteditable data-ref="buyer">McDonalds</div> 
    <div contenteditable data-ref="order">145632</div> 
  </div> 
  <div class="item"> 
    <div contenteditable data-ref="name">Big Mac</div> 
    <div contenteditable data-ref="quantity">5</div> 
    <div contenteditable data-ref="rate">20.00</div> 
  </div> 
  <div class="item"> 
    <div contenteditable data-ref="name">Small Mac</div> 
    <div contenteditable data-ref="quantity">10</div> 
    <div contenteditable data-ref="rate">10.00</div> 
  </div> 
</div> 
     
<button id="Loop">Loop</button>

.........................run snippets full screen for better view

second method

const jsonObj      = []; 
const inVoicesElms = document.querySelectorAll('.invoice div'); 
 
Loop.onclick=_=> 
  { 
  jsonObj.push( { Invoice: getInVoicesValues() } ) 
  console.clear() 
  console.log( jsonObj ) 
  } 
function getInVoicesValues()  
  { 
  let rep  = { headers:{}, items:[] } 
    , cur  = null 
    ; 
  inVoicesElms.forEach(el => 
    { 
    if (el.matches('.header')) 
      { 
      cur = rep.headers 
      } 
    else if (el.matches('.item')) 
      { 
      cur = {} 
      rep.items.push(cur) 
      } 
    else // (el.matches('[contenteditable]')) 
      { 
      cur[el.getAttribute('data')] = el.textContent 
      } 
    }) 
  return rep 
  }
.as-console-wrapper { max-height: 100% !important; width: 50% !important; 
    top: 0; left: 50% !important; 
  }
<div class="invoice"> 
  <div class="header"> 
    <div contenteditable data="date">15-Jan-2020</div> 
    <div contenteditable data="buyer">McDonalds</div> 
    <div contenteditable data="order">145632</div> 
  </div> 
  <div class="item"> 
    <div contenteditable data="name">Big Mac</div> 
    <div contenteditable data="quantity">5</div> 
    <div contenteditable data="rate">20.00</div> 
  </div> 
  <div class="item"> 
    <div contenteditable data="name">Small Mac</div> 
    <div contenteditable data="quantity">10</div> 
    <div contenteditable data="rate">10.00</div> 
  </div> 
</div> 
     
<button id="Loop">Loop</button>

Rent Charter Buses Company
READ ALSO
How do I convert this jquery code to JavaScript?

How do I convert this jquery code to JavaScript?

This is the jquery code below:

169
scrollIntoView() works in console but not not when in in the site code

scrollIntoView() works in console but not not when in in the site code

I have a div which contains a table for tabs in my site navigationI have the div set to overflow when in mobile like this:

221
How to avoid repeating large amounts of code and apply the same rule to multiple classes

How to avoid repeating large amounts of code and apply the same rule to multiple classes

I have 12 images for example and on image click I want to hide the 11 other images and increase the clicked upon image to full screen

200
remove duplication from jQuery array

remove duplication from jQuery array

I have a page that can have the same article twice or more in it i have an ajax search in this page ,when i do the search with the name of article it shows twice if there is two of it in this page , so i want to remove the duplicate and to display every article...

183