Home > Software engineering >  foreach breaks and gives error when try to load this json
foreach breaks and gives error when try to load this json

Time:12-31

i am trying to load this json in my page but foreach break and gives error as the number is not in serial

if we provide the number in serial it works. serial means in incremental this is my json

{
    "": {
        "id": "",
        "name": "",
        "reply": "",
        "parent": "",
        "actions": []
    },
    "0": {
        "id": "0",
        "name": "",
        "reply": "",
        "parent": "",
        "actions": [
            "01",
            "02",
            "03",
            "04",
            "06",
            "07"
        ]
    },
    "01": {
        "id": "01",
        "name": "Order Status",
        "reply": "Please provide your order number",
        "parent": "0",
        "actions": [
            "011"
        ]
    },
    "07": {
        "id": "07",
        "name": "Book Appointment",
        "reply": "Book Appoinme",
        "parent": "0",
        "actions": []
    },
    "welcomeMssg": "Do you need help with :-",
    "startId": "0",
    "scName": "test name"
}

and this is my javascript

var scenario = "";
var fdata = null;

function getScenarioData(scid, cid) {
  scenario = scid;
  var obj = {
    client: cid,
    scenario: scid,
  };
  $.ajax({
    type: "GET",
    url: "getdata.php",
    data: obj,
    success: function (data) {
      data = JSON.parse(data);
      fdata = data;
      console.log(fdata);
      document.getElementById("welcomeMessage").value = data.welcomeMssg;
      document.getElementById("scenarioName").value = data.scName;
      scenarioName = data.scName;
      welcomeMessage = data.welcomeMssg;
      start = data.startId;
      buttons = data;
      document.getElementById("main1").style.display = "block";
      document.getElementById("entry").style.display = "none";
      ac = buttons[start].actions;
      for(let k in buttons) {
        if(buttons[k].actions){
          count[k] = buttons[k].actions.length 1;
        }
      }
      console.log(count);
      ac.forEach(e => {
        var input = document.createElement("input");
        input.type = "text";
        input.className = "replybox m-1 p-2 form-control";
        input.placeholder = "reply";
        input.style.display = "inline";
        input.value = buttons[e].name;  
        input.id = buttons[e].id;
        var id = buttons[e].id;
        input.onclick = function () {
            addRes(id, buttons[e].parent);
        };
     //   input.onkeyup = function () {
                input.onchange = function () {
            buttons[id].name = document.getElementById(id).value;
            if (document.getElementById("show"   id)) {
            document.getElementById("show"   id).innerHTML =
                "(for "   document.getElementById(id).value   ")";
            }
        };
        var d = document.createElement("div");
        var s = document.createElement("span");
        d.id = "reply" id;
        s.innerHTML = `<i class='fa fa-times-circle circle' aria-hidden='true' onclick='deleteButton("${id}");' style='font-size:15px;cursor:pointer;margin-left:-10px;;'></i>`;
        d.appendChild(input);
        d.appendChild(s);
        document.getElementById("replies0").appendChild(d);
      });
  },
  error: function (e) {
    console.log(e.message);
  },
 });
}

if i change the json output to 2 instead of 7 it works fine. i am confused is it mandatory to have data in incremental if we are using foreach

when i say if i replace 7 with 2 means this

"07": {
        "id": "07",
        "name": "Book Appointment",
        "reply": "Book Appoinme",
        "parent": "0",
        "actions": []
    },

here is live site for demo https://way2enjoy.com/shopify/1/whatsapp-chat/bot/1/2/edit_scenario.php?client=50457

any help will be great

i get this error at console

Uncaught TypeError: Cannot read properties of undefined (reading 'name')
    at edit_scenario.js:39
    at Array.forEach (<anonymous>)
    at Object.success (edit_scenario.js:33)
    at c (jquery.min.js:2)
    at Object.fireWith [as resolveWith] (jquery.min.js:2)
    at l (jquery.min.js:2)
    at XMLHttpRequest.<anonymous> (jquery.min.js:2)

CodePudding user response:

You are looping over ["01", "02", "03", "04", "06", "07"] and try to access each of these keys on the returned object. Yet data["02"], data["03"], etc. do not exist, thus resulting in undefined.

ac.forEach(e => {
  // …
  input.value = buttons[e].name;  
  input.id = buttons[e].id;
  var id = buttons[e].id;
  input.onclick = function () {
    addRes(id, buttons[e].parent);
  };
  // …
});

In the above code ac refers to buttons[start].actions or simply put buttons["0"].actions which is ["01", "02", "03", "04", "06", "07"].

You then start iterating over these actions, trying to use each element as key to access the object. buttons[e] is buttons["01"], buttons["02"], etc. Since you only have the keys "01" and "07" present, all other attempts will result in undefined.

This produces an error because buttons[e].name -> buttons["02"].name -> undefined.name -> "Uncaught TypeError: Cannot read properties of undefined (reading 'name')".

This can be solved in three ways. Two of which are the responsibility of the server.

  1. Client-side solution: Skip the elements if they are not present within the object.

    // Only select the actions that are actually present in `buttons`.
    ac = buttons[start].actions.filter(e => e in buttons);
    

    Or alternatively:

    ac.forEach(e => {
      // Skip the iteration if `e` is not present in `buttons`.
      if (!(e in buttons)) return;
    
      // …
    });
    
  2. Server-side solution 1: Send only the actions to the client that are actually present in the response.

    {
      // …
      "0": {
        "id": "0",
        "name": "",
        "reply": "",
        "parent": "",
        "actions": ["01", "07"]
      },
      // …
    }
    
  3. Server-side solution 2: Instead of reducing the actions you could also send all the related objects.

    {
      // …
      "0": {
        // …
        "actions": ["01", "02", "03", "04", "06", "07"]
      },
      "01": { /* … */ },
      "02": { /* … */ },
      "03": { /* … */ },
      "04": { /* … */ },
      "05": { /* … */ },
      "06": { /* … */ },
      "07": { /* … */ },
      // …
    }
    
  • Related