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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.