Search code examples
javascriptcoding-styleunderscore.jsclient-side-templating

best method to build table headings and data separately using same json in underscore.js?


I'm working on my first site using client-side templating, and so far so good. I'm just looking to achieve the best performance for the code below.

I'm given json in this format:

[
    {
        "slidenumber": "slide0",
        "title": "Sample Data 1",
        "slideDelay": "2000",
        "months": [
            {
                "Jan": "10.3",
                "Dec": "65",
                "Nov": "87",
                "Oct": "80",
                "Sep": "70",
                "Aug": "100"
            }
        ]
    },
    {
        "slidenumber": "slide1",
        "title": "Sample Data 2",
        "slideDelay": "2000",
        "months": [
            {
                "Jul": "10",
                "Jun": "20",
                "May": "30",
                "Apr": "40",
                "Mar": "50",
                "Feb": "60"
            }
        ]
    }
]

and using the underscore.js template below:

     _.each(slides, function(slide){ %>
       <li data-slide-delay="<%= slide.slideDelay %>">
         <h1><%= slide.title %></h1>
          <table class="table">
            <thead>
              <tr>
                <% 
                  _.each( slide.months, function(month) {
                    if (_.isObject(month)) {
                     _.each(month, function(value, key) {%>
                        <th><%= key %></th>
                      <%}) 
                    }
                  });%>
            </tr>
          </thead>
          <tbody>
              <tr>
                <% 
                  _.each( slide.months, function(month) {
                    if (_.isObject(month)) {
                     _.each(month, function(value, key) {%>
                        <td><%= value %></td>
                      <%}) 
                    }
                  });%>
            </tr>
          </tbody>
        </table>
      </li>

Basically, I'm building a slideshow using the data above, so each "slide" has specific fields title, delay, etc., months on the other hand has data inside of it. I'm building an <li> for each slide and within in that a horizontal <table>, in that table I'm building <th> for the month (i.e. Jan, Feb, Mar, etc.) and then I'm separating the month value in <td>'s

Rather than do two _.(each statements with the same data (but echoing different values) as I'm doing above, what's the best method to achieve the desired output?


Solution

  • If you preprocess your JSON data before using it for printing you can lower your number of nested _.each.

    You will still have to use two _.each statements to display your data.

    The real benefit of doing this, is that you can centralize your data processing and you decouple your data from your display by adding a level of abstraction. If your data structure change overtime, you would only have to modify the data processing part and your "view" would remain the same

    var headers = [];
    var content = [];
    var rows = 0;
    _.each(slides, function(slide){
        if (rows % 2 == 0) {
            content.push([])
        }
        _.each(slide.months, function(month) {
            if (_.isObject(month)) {
                _.each(month, function(value, key) {
                    headers.push(key);
                    content[content.length - 1].push(value);
                })
            }
            rows += 1;
        })
    });
    
    console.log(headers);
    console.log(content);
    

    The headers part would be the months label and the content part would contain all your rows of data in the form of nested arrays of data.

    * I used a row counter to merge the two parts of the year (from slide0 and slide1) with a modulus, but you might have to add some validation for this section to make sure you remain coherent in your table