Search code examples
node.jsexpresshandlebars.js

Parse JSONString and then iterate over the array in handlebars


I have data like this :

{ "data" : [
 {
   "query": "Hello",
   "response": "asad"
 },
{
"query": "Tell Weather dale",
"response": "[{\"datetime\":\"2024-01-26\",\"tempmax\":21.5,\"tempmin\":7,\"temp\":14,\"humidity\":59.2,\"precip\":0,\"precipprob\":0,\"windspeed\":5.8,\"cloudcover\":61.6,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-27\",\"tempmax\":23.2,\"tempmin\":11.2,\"temp\":16.3,\"humidity\":38.2,\"precip\":0,\"precipprob\":0,\"windspeed\":9.4,\"cloudcover\":32.5,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-28\",\"tempmax\":24,\"tempmin\":11.7,\"temp\":17.2,\"humidity\":39.9,\"precip\":0,\"precipprob\":0,\"windspeed\":10.4,\"cloudcover\":54.9,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-29\",\"tempmax\":25,\"tempmin\":12.6,\"temp\":18.2,\"humidity\":42.1,\"precip\":0,\"precipprob\":0,\"windspeed\":9.7,\"cloudcover\":41.3,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-30\",\"tempmax\":25.3,\"tempmin\":13.8,\"temp\":18.8,\"humidity\":48.2,\"precip\":0,\"precipprob\":0,\"windspeed\":6.1,\"cloudcover\":66.5,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-31\",\"tempmax\":26.2,\"tempmin\":14.6,\"temp\":19.5,\"humidity\":48.4,\"precip\":0,\"precipprob\":0,\"windspeed\":9.4,\"cloudcover\":14.9,\"conditions\":\"Clear\"}]"
}
] }

wherein the response could either be a normal string or a JSONString. I want to parse the json string, iterate over the array and show the individual keys like datetime, temp etc.

I'm able to parse the JSON but I'm unable to then iterate over it handlebars template.

Can someone please help me on how the template and the helper functions should look like?


Solution

  • The first thing I feel I need to say is that your team is doing something wrong if there is a property of the response object whose value can be either a string or a stringified JSON of arbitrarily-shaped data.

    It my opinion that it is the back-end response that needs to worked on.

    However, for the fun of the challenge, let's think about how we could solve this in the template.

    One thing that is unclear to me is that when the response is stringified JSON, if that JSON will always have the same structure or not. For simplicity, I am going to assume that it will always be an array of objects.

    As you stated in the comments, a JSON.parse is going to error when given input that is not stringified JSON. Therefore, we would need to use a try/catch to catch that error and just return the response unparsed, as we will assume it is a string.

    We could create a Block Helper that would allow us to define the template to be used when response can be JSON parsed. Our helper will just return the unaltered response when it can't be JSON parsed.

    const template = Handlebars.compile(`
    {{#each data}}
      <p>Query: {{query}}</p>
      <p>Response:</p>
      {{#parseResponse response}}
        {{#each this}}
          <ul>
            {{#each this}}
              <li>{{@key}}: {{this}}</li>
            {{/each}}
          </ul>
        {{/each}}
      {{/parseResponse}}
    {{/each}}
    `);
    
    Handlebars.registerHelper('parseResponse', function (response, options) {
      try {
        return options.fn(JSON.parse(response));
      } catch (err) {
        // console.error(err);
        // We will ignore the error and return `response` below
      }
      
      return response;
    });
    
    const data = {
      "data": [{
          "query": "Hello",
          "response": "asad"
        },
        {
          "query": "Tell Weather dale",
          "response": "[{\"datetime\":\"2024-01-26\",\"tempmax\":21.5,\"tempmin\":7,\"temp\":14,\"humidity\":59.2,\"precip\":0,\"precipprob\":0,\"windspeed\":5.8,\"cloudcover\":61.6,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-27\",\"tempmax\":23.2,\"tempmin\":11.2,\"temp\":16.3,\"humidity\":38.2,\"precip\":0,\"precipprob\":0,\"windspeed\":9.4,\"cloudcover\":32.5,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-28\",\"tempmax\":24,\"tempmin\":11.7,\"temp\":17.2,\"humidity\":39.9,\"precip\":0,\"precipprob\":0,\"windspeed\":10.4,\"cloudcover\":54.9,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-29\",\"tempmax\":25,\"tempmin\":12.6,\"temp\":18.2,\"humidity\":42.1,\"precip\":0,\"precipprob\":0,\"windspeed\":9.7,\"cloudcover\":41.3,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-30\",\"tempmax\":25.3,\"tempmin\":13.8,\"temp\":18.8,\"humidity\":48.2,\"precip\":0,\"precipprob\":0,\"windspeed\":6.1,\"cloudcover\":66.5,\"conditions\":\"Partially cloudy\"},{\"datetime\":\"2024-01-31\",\"tempmax\":26.2,\"tempmin\":14.6,\"temp\":19.5,\"humidity\":48.4,\"precip\":0,\"precipprob\":0,\"windspeed\":9.4,\"cloudcover\":14.9,\"conditions\":\"Clear\"}]"
        }
      ]
    };
    
    const output = template(data);
    
    document.body.innerHTML = output;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js"></script>