0

My application is MVC 5, I am using the following Ajax to generate an array:

$.ajax({
            type: "Post",
            url: '@Url.Action("Getthereport", "Surveys")',
            async: false,
            cache: false,
            dataType: "json",
            data: { 'test': "All" },
            success: function (result) {

                if (result && result.Grid.length > 0) {
                    for (let i = 0; i < result.Grid.length; i++) {
                        jsonData.push({
                            Question: result.Grid[i].Body,
                            QuestionId: result.Grid[i].QuestionId,
                            myData: { name: result.Grid[i].name, value: result.Grid[i].value }
                          });
                    };
                }
               },
            complete: function () {
               reduce();
            },
            error: function(err) {
                alert(err.status + " : " + err.statusText);
            }
        });

I generates the following:

var jsonData = [
            {
                Question: "Was the training useful?",
                QuestionId: 1,
                myData: [{ name: 'No', value: 1 }] },
            {
                Question: "Was the training useful?",
                QuestionId: 1 ,
                myData: [{ name: 'Yes', value: 1 }]
        }];

to merge the objects, I use:

const result = Object.values(jsonData.reduce((acc, obj) => {
  if (!acc[obj.QuestionId]) {
    acc[obj.QuestionId] = obj;
  } else {
    acc[obj.QuestionId].myData = acc[obj.QuestionId].myData.concat(obj.myData);
  }
  return acc;

Works great if the array is hardcoded and generates:

var jsonData = [
        {
            Question: "Was the training useful?",
            QuestionId: 1,
            myData: [{ name: 'No', value: 1 },
                     { name: 'Yes', value: 1 }] 
          }]; 

However, if the array is generated by Ajax call, I get the following error:

 acc[obj.QuestionId].myData.concat is not a function

I tried to run the reduce script on Ajax complete and directly both did not work.

12
  • What is acc? Can you add console.log(acc) and console.log(typeof acc)? Commented Apr 13, 2022 at 1:55
  • 1
    Yes, probably because in one case !acc[obj.QuestionId] returns true and in the other case it returns false. The else block causes the error. How is "console.log(acc) is not defined" possible?. Where do you run the code? I assume in a modern browser? Please provide a minimal reproducible example. Commented Apr 13, 2022 at 2:07
  • 1
    I see two possible reasons. Either How to return the response from an asynchronous call or in one case you have a JSON string and in the other a JavaScript object. In your code snippet in the question jsonData doesn't contain JSON data, but a response contains JSON data. What is the difference between JSON and Object Literal Notation? This is confusing for many people. Commented Apr 13, 2022 at 2:10
  • 1
    true, but to get to myData.concat at all the data has to be valid, it could be just another type than Array? (if it's any type that doesn't implement a concat method it throws that error. ie. boolean, number, object ) Commented Apr 13, 2022 at 9:16
  • 1
    @hncl I just read your code and you're pushing an object with myData as an object in your ajax call jsonData.push({Question: result.Grid[i].Body, QuestionId: result.Grid[i].QuestionId, myData: { name: result.Grid[i].name, value: result.Grid[i].value }}) either wrap it in an array, or change your reduce to handle it as an object. Commented Apr 13, 2022 at 9:50

1 Answer 1

1

In the success property of your ajax call options you're pushing myData as an object, not as an array

  success: function (result) {

    if (result && result.Grid.length > 0) {
      for (let i = 0; i < result.Grid.length; i++) {
        jsonData.push({
          Question: result.Grid[i].Body,
          QuestionId: result.Grid[i].QuestionId,
          myData: { name: result.Grid[i].name, value: result.Grid[i].value }
        });
      };
    }
  },

Which means that the output is not as you stated but rather

var jsonData = [
  {
    Question: "Was the training useful?",
    QuestionId: 1,
    myData: { name: 'No', value: 1 } //<-- Objects not arrays
  },
  {
    Question: "Was the training useful?",
    QuestionId: 1,
    myData: { name: 'Yes', value: 1 }
  }
];

You can either declare it as an array at that stage to generate the output you originally posted,

      for (let i = 0; i < result.Grid.length; i++) {
        jsonData.push({
          ...
          myData: [{ name: result.Grid[i].name, value: result.Grid[i].value }]
        });
      };

or adjust your reduce.

var jsonData = [
  {
    Question: "Was the training useful?",
    QuestionId: 1,
    myData: { name: 'No', value: 1 }
  },
  {
    Question: "Was the training useful?",
    QuestionId: 1,
    myData: { name: 'Yes', value: 1 }
  }
];


const result = Object.values(jsonData.reduce((acc, obj) => {
  acc[obj.QuestionId] ??= { ...obj, myData: [] };
  acc[obj.QuestionId].myData.push(obj.myData);
  return acc;
}, {}));

console.log(JSON.stringify(result, null, 2))

Sign up to request clarification or add additional context in comments.

1 Comment

thank you; I used myData: [{ name: result.Grid[i].name, value: result.Grid[i].value }]. It works great.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.