0

I have multiple <div> elements, and they have 3 things in common (<h3>, <textarea>, <img>). On a button click, I need to get a JSON result (shared below).

Here is what I have tried, but I'm unable to convert to JSON, but I am able to convert it to separate arrays.

function get_json() {
  var groups = Array.from(document.querySelectorAll(".StackedList"));

  var imgs = groups.map(function(group) {
    return Array.from(group.querySelectorAll("img")).map(function(item) {
      return new URL(item.src).pathname.substring(1);
    });
  });

  var desc = groups.map(function(group) {
    return Array.from(group.querySelectorAll("textarea")).map(function(item) {
      return item.value
    });
  });

  var h3text = groups.map(function(group) {
    return Array.from(group.querySelectorAll("h3")).map(function(item) {
      return item.innerText
    });
  });
  
  alert(imgs + desc + h3text)
  return imgs, desc, h3text
}
<div class="StackedList" id="group1">
  <h3 id="c1" style="display:inline" contenteditable="true">Item 1</h3>
  <textarea id="desc1" placeholder="Enter the description" name="w3review"></textarea>
  <img class="draggable" src="http://localhost:99/10.jpg" />
  <img class="draggable" src="http://localhost:99/11.jpg" />
  <img class="draggable" src="http://localhost:99/12.jpg" />
</div>

<div class="StackedList" id="group2">
  <h3 id="c2" style="display:inline" contenteditable="true">Item 2</h3>
  <textarea id="desc2" placeholder="Enter the description" name="w3review"></textarea>
  <img class="draggable" src="http://localhost:99/8.jpg" />
  <img class="draggable" src="http://localhost:99/7.jpg" />
  <img class="draggable" src="http://localhost:99/2.jpg" />
</div>

<div class="StackedList" id="group3">
  <h3 id="c3" style="display:inline" contenteditable="true">Item 3</h3>
  <textarea id="desc3" placeholder="Enter the description" name="w3review"></textarea>
  <img class="draggable" src="http://localhost:99/1.jpg" />
</div>

<input type="button" value="Get json" onclick="get_json()">

Expected output

I need to get JSON on a button click.

{
  "Item 1": {
    "descrption": "Entered text value",
    "images": ["10.jpg", "11.jpg", "12.jpg"]
  },
  "Item 2": {
    "descrption": "Entered text value",
    "images": ["8.jpg", "7.jpg", "2.jpg"]
  },
  "Item 3": {
    "descrption": "Entered text value",
    "images": ["1.jpg"]
  }
}
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
Sathish Kumar
  • 39
  • 1
  • 5

5 Answers5

1

You are grabbing values into arrays but has to be converted into an JSON object.

You can simplify this using .reduce & .map function as below

function get_json(){
const groups = Array.from(document.querySelectorAll(".StackedList"));

const result = groups.reduce((res,obj)=>{
  const name = obj.querySelector('h3').textContent
  res[name] = {
     descrption:  obj.querySelector('textarea').value,
    images: Array.from(obj.querySelectorAll('img')).map(item=>new URL(item.src).pathname.substring(1))
  };
  return res;
},{});
console.log(result)
return result;
}
<div class="StackedList" id="group1">
  <h3 id="c1" style="display:inline" contenteditable="true">Item 1</h3>
  <textarea id="desc1" placeholder="Enter the description" name="w3review"></textarea>
  <img class="draggable" src="http://localhost:99/10.jpg" />
  <img class="draggable" src="http://localhost:99/11.jpg" />
  <img class="draggable" src="http://localhost:99/12.jpg" />
</div>

<div class="StackedList" id="group2">
  <h3 id="c2" style="display:inline" contenteditable="true">Item 2</h3>
  <textarea id="desc2" placeholder="Enter the description" name="w3review"></textarea>
  <img class="draggable" src="http://localhost:99/8.jpg" />
  <img class="draggable" src="http://localhost:99/7.jpg" />
  <img class="draggable" src="http://localhost:99/2.jpg" />
</div>

<div class="StackedList" id="group3">
 <h3 id="c3" style="display:inline" contenteditable="true">Item 3</h3>
 <textarea id="desc3" placeholder="Enter the description" name="w3review"></textarea> 
 <img class="draggable" src="http://localhost:99/1.jpg" />
</div>

<input type="button" value="Get json" onclick="get_json()">
Jagdish Idhate
  • 7,513
  • 9
  • 35
  • 51
1

This would be a quick solution:

It is creating a new object with the name json. The code iterates through your h3text array. For each entry, a new object is created (newEntry), so that your json object becomes a nested object. In the newEntry object, two keys description (String) and ìmages (Array) are created. After that, I check if a key (for instance "item 1" already exist in json. When not, a new key with the name h3text[i] is created.

For testing you can use console.log(json) to check if it fits your needs.

Attention: I do not check if desc[i][0] and imgs[i] exist. So for a proper loop you should check them for not being undefined.

  let json = {};
  for(let i = 0; i < h3text.length; i++){
    let newEntry = {
        "description": desc[i][0],
        "images": imgs[i]
    }
    // Only save ""item1" when there is no key with "item1" already
    if(!json.hasOwnProperty(h3text[i])){
       json[h3text[i]] = newEntry;
    }
    
  }

function get_json()
{
var groups = Array.from(document.querySelectorAll(".StackedList"));

var imgs = groups.map(function (group) {
            return Array.from(group.querySelectorAll("img")).map(function (item) {
                return new URL(item.src).pathname.substring(1);
            });
        });

var desc = groups.map(function (group) {
           return Array.from(group.querySelectorAll("textarea")).map(function (item) {
                return item.value
            });
        });

var h3text = groups.map(function (group) {
           return Array.from(group.querySelectorAll("h3")).map(function (item) {
                return item.innerText
            });
        });


    let json = {};
  for(let i = 0; i < h3text.length; i++){
    let newEntry = {
        "description": desc[i][0],
        "images": imgs[i]
    }
    // Only save ""item1" when there is no key with "item1" already
    if(!json.hasOwnProperty(h3text[i])){
       json[h3text[i]] = newEntry;
    }
    
  }
  console.log(json)
  return json

}
<div class="StackedList" id="group1">
  <h3 id="c1" style="display:inline" contenteditable="true">Item 1</h3>
  <textarea id="desc1" placeholder="Enter the description" name="w3review"></textarea>
  <img class="draggable" src="http://localhost:99/10.jpg" />
  <img class="draggable" src="http://localhost:99/11.jpg" />
  <img class="draggable" src="http://localhost:99/12.jpg" />
</div>

<div class="StackedList" id="group2">
  <h3 id="c2" style="display:inline" contenteditable="true">Item 2</h3>
  <textarea id="desc2" placeholder="Enter the description" name="w3review"></textarea>
  <img class="draggable" src="http://localhost:99/8.jpg" />
  <img class="draggable" src="http://localhost:99/7.jpg" />
  <img class="draggable" src="http://localhost:99/2.jpg" />
</div>

<div class="StackedList" id="group3">
 <h3 id="c3" style="display:inline" contenteditable="true">Item 3</h3>
 <textarea id="desc3" placeholder="Enter the description" name="w3review"></textarea> 
 <img class="draggable" src="http://localhost:99/1.jpg" />
</div>

<input type="button" value="Get json" onclick="get_json()">
michaelT
  • 1,533
  • 12
  • 41
1

You can query for the elements inside your reducer. Grabbing the filenames from the URL is fairly simple. Just grab the path of the URL object and locate the last part.

Note: Looks like you come from a python background (using snake-case) i.e. get_json, but JavaScript conventions use C-like variable/class camel-case e.g. getJson or getJSON. As for your HTML, attributes are typically kebab-case e.g. class="stacked-list".

const grabFilename = (url) =>
  (pathname =>
    (index => -1 !== index
      ? pathname.substring(index + 1)
      : pathname)
    (pathname.lastIndexOf('/'))
  )(new URL(url).pathname);

function getJson() {
  const json = [...document.querySelectorAll('.StackedList')].reduce((res, group) => {
    return {
      ...res,
      [group.querySelector('h3').textContent]: {
        description: group.querySelector('textarea').value,
        images: [...group.querySelectorAll('img')].map(img => {
          return grabFilename(img.getAttribute('src'))
        })
      }
    }
  }, {});
  
  console.log(json);
}
<div class="StackedList" id="group1">
  <h3 id="c1" style="display:inline" contenteditable="true">Item 1</h3>
  <textarea id="desc1" placeholder="Enter the description" name="w3review">Entered text value</textarea>
  <img class="draggable" src="http://localhost:99/10.jpg" />
  <img class="draggable" src="http://localhost:99/11.jpg" />
  <img class="draggable" src="http://localhost:99/12.jpg" />
</div>

<div class="StackedList" id="group2">
  <h3 id="c2" style="display:inline" contenteditable="true">Item 2</h3>
  <textarea id="desc2" placeholder="Enter the description" name="w3review">Entered text value</textarea>
  <img class="draggable" src="http://localhost:99/8.jpg" />
  <img class="draggable" src="http://localhost:99/7.jpg" />
  <img class="draggable" src="http://localhost:99/2.jpg" />
</div>

<div class="StackedList" id="group3">
  <h3 id="c3" style="display:inline" contenteditable="true">Item 3</h3>
  <textarea id="desc3" placeholder="Enter the description" name="w3review">Entered text value</textarea>
  <img class="draggable" src="http://localhost:99/1.jpg" />
</div>

<input type="button" value="Get json" onclick="getJson()">
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

You can convert the HTML to json, first get the DOM elements, parse them and then use JSON.stringify on the resulted object. Like here: Map HTML to JSON

piir
  • 41
  • 5
0

All answers are good. Here is another one. But the choice is yours!

    function get_json() {
    var groups = document.querySelectorAll(".StackedList");
    //create a main object to store all the div objects
    var listObj = {
        items: []
    };

    groups.forEach(item => {
        //get images 
        var allimages = Array.from(document.querySelectorAll('#' + item.id + ' > img'));
        //div object
        var listItem = {
            //get title 
            title: document.querySelector('#' + item.id + ' > h3').innerHTML,
            //get description
            desc: document.querySelector('#' + item.id + ' > textarea').value,
            //get image name with extension 
            images: allimages.map(item => {
                return item.src.replace(/http:.*?\d\//, '');
            })
        }
        //push the newly created object to main object's items array
        listObj.items.push(listItem);
    });
    //output the data
    alert(JSON.stringify(listObj));
}
Back2Lobby
  • 534
  • 6
  • 12