dustjs xpath parent equivalent

135 Views Asked by At

I'm trying to do something pretty simple: I'd like to show the NBA teams by conference, but that isn't the structure of the JSON.

I don't want to ask for a REST service structure change, i.e., make teams a child array of conference node.

This is a presentation issue, i.e., the JSON has the data I need, but how can I present it using dustjs?

You can see my jsfiddle attempt here: xpath equivalent jsdust

<script id="league-template2">
    <div class="conference"> 
    <h3>[I WANT TO PUT THE CONFERENCE NAME HERE EG EASTERN] Conference</h3>
    {#teams}   
        <ul>
            {#properties}            
                {@eq key=name value="numeric"}
                    <li class="teamName teamdd_{value}">
                        <div class="logo-nba-small nba-small-[I WANT TO PUT THE ABBV HERE EG PHI]"><a>[I WANT TO PUT TEAM NAME HERE EG 76ERS]</a></div>
                    </li>
                {/eq}
            {/properties}
        </ul>
   {/teams}
   </div>
</script>
<div id="output3"></div><br />


    $(document).ready(function() {
    var league2014 = {
    "teams": [{
        "properties": [{
        "years": null,
        "name": "conference",
        "value": "eastern"
        }, {
        "years": null,
        "name": "abbv",
        "value": "phi"
        }, {
        "years": null,
        "name": "numeric",
        "value": "20"
        }],
        "name": "76ers"
    }, {
        "properties": [{
        "years": null,
        "name": "conference",
        "value": "western"
        }, {
        "years": null,
        "name": "abbv",
        "value": "mem"
        }, {
        "years": null,
        "name": "numeric",
        "value": "29"
        }],
        "name": "grizzlies"
    }, {
        "properties": [{
        "years": null,
        "name": "conference",
        "value": "eastern"
        }, {
        "years": null,
        "name": "abbv",
        "value": "was"
        }, {
        "years": null,
        "name": "numeric",
        "value": "27"
        }],
        "name": "wizards"
    }]
    }    
    var source3 = $("#league-template2").html();
    var compiled3 = dust.compile(source3, "intro3");
    dust.loadSource(compiled3);
    dust.render("intro3", league2014, function(err, out) {
    $("#output3").html(out);
    });
});
2

There are 2 best solutions below

12
On

Try this:

<div class="conference"> 
{#teams}
  {#properties teamName=name}
    {@select key=name}
      {@eq value="conference"}
        <h3>{value} Conference</h3><ul>
      {/eq}
      {@eq value="numeric"}
        <li class="teamName teamdd_{value}">
      {/eq}
      {@eq value="abbv"}
        <div class="logo-nba-small nba-small-{value}"><a>{teamName}</a></div>
        </li>
      {/eq}
    {/select}
  {/properties}
  </ul>
{/teams}
</div>
9
On

Here's how I would do it to fit your requirements while keeping the template simple.

Template:

<div class="conference"> 
{#teamsByConference}
  <h3>{conference}</h3>
  <ul>
  {#teams}
    <li class="teamName teamdd_{numeric}">
      <div class="logo-nba-small nba-small-{abbv}"><a>{name}</a></div>
    </li>
  {/teams}
  </ul>
{/teamsByConference}
</div>

Context:

{
    // This is a Dust context function. It's called a handler!
    // It gets called by Dust when you try to access it. Handlers act like variables in templates
    // But they can do much more than just return a value. They can make async AJAX requests,
    // create new data, and all sorts of things. They're (in my opinion) one of the best features of Dust.
    // https://github.com/linkedin/dustjs/blob/master/docs/api.md#handlers
    "teamsByConference": function(chunk, context, bodies, params) {
      // Get the teams variable from the Dust context. You can use this.teams, but
      // that won't walk the context tree in case this function is at a different level
      var teams = context.get("teams"),
          conferences = {},
          conferenceList = [],
          conference,
          x;

      // I'm using ECMAScript 5 just to save space
      // Transform the JSON into the format we want and store it in conferences
      teams.forEach(function(team) {
        // Teams have an array of properties, but it'd be much more JSON-like if they
        // were keys in an Object. So I'll reduce the array to a single object.
        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
        var newTeam = team.properties.reduce(function(acc, prop) {
          acc[prop.name] = prop.value;
          return acc;
        }, {});
        newTeam.name = team.name;

        // Combine teams by their conference
        conferences[newTeam.conference] = conferences[newTeam.conference] || [];
        conferences[newTeam.conference].push(newTeam);
      });

      // Transform the conference object into an array so Dust iterates over it
      for(conference in conferences) {
        conferenceList.push({ conference: conference, teams: conferences[conference] });
      }

      // At this point we have an array of conferences. Each conference contains an array of teams!
      // Iterate over the returned list of conferences by returning it
      // Dust chunks and contexts are super-cool and you can read the source to learn all about them
      return conferenceList;
    },

    "teams": [...]
    } 

I'm using a context helper to format the data in your context the way that it should be. This keeps any grouping or membership logic out of your template.

If you don't like this philosophy, that's OK-- but this is Dust's philosophy.