Search code examples
javascriptarraystemplateshelperjsrender

Is it possible to use an array as a parameter to a jsrender helper function?


I have a bit of javascript code I use to retrieve the value of a property from an array of objects by matching an identifying property value in those same objects.

plantArray.find(p => p.PlantCode.toUpperCase() == code.toUpperCase()).PlantName;

I'd like to use this in a helper function so I can use it while rendering a template.

function plantNameFromCode(code, plantArray) {
  if (plantArray)
  {
    if (typeof plantArray == "string")
      return plantArray;

    plantname = plantArray.find(p => p.PlantCode.toUpperCase() == code.toUpperCase()).PlantName;
    return plantname;
  }
  else
  {
    return code;
  }
}

$.views.helpers({
  plantNameFromCode: plantNameFromCode
});

The template looks like this:

<script id="test-plantnamefromcode-template" type="text/x-jsrender">
  {{!-- selectedplants is an array of plant codes --}}
  {{for selectedplants itemVar="~plant"}}
    Plant Code: {{:~plant}}<BR>
    Plant Test: {{:~plantNameFromCode(~plant, "TEST")}}<BR>
    Plant Name: {{:~plantNameFromCode(~plant, plantlist)}}<BR>
  {{/for}}
</script>

Data looks like this:

var data = {
  selectedplants: ["PlantCode2", "PlantCode4"],
  plantlist: [
    {
      PlantCode: 'PlantCode1',
      PlantName: 'Plant Name 1'
    },
    {
      PlantCode: 'PlantCode2',
      PlantName: 'Plant Name 2'
    },
    {
      PlantCode: 'PlantCode3',
      PlantName: 'Plant Name 3'
    },
    {
      PlantCode: 'PlantCode4',
      PlantName: 'Plant Name 4'
    },
    {
      PlantCode: 'PlantCode5',
      PlantName: 'Plant Name 5'
    },
    {
      PlantCode: 'PlantCode6',
      PlantName: 'Plant Name 6'
    },
  ]
};

I render the template this way:

var template = $.templates("#test-plantnamefromcode-template");
html = template.render(data);
$("#main").html(html);

The helper function parameter plantArray is undefined when the function is called with an array as the second parameter during rendering. I'm wondering if an array can be passed to the helper function in this manner.

I've tried passing the array from within the template in a variety of ways. I've used ~plantlist, :~plantlist, :plantlist, and plantlist. None of these formats seem to pass the array into the helper function

If I pass in a string variable it is seen by the helper function, as is shown in the TEST line in the template definition.

Is there a way I need to reference the array when providing it as a parameter? Are arrays allowed as parameters to a helper function?


Solution

  • Yes, you can pass an array to a helper function.

    Your issue here is that you are not actually passing an array, but instead an undefined property.

    To explain: you have a view hierarchy, with the parent view having your data object as data context, with properties selectedplants and plantlist. You are iterating over the selectedplants. Within the child view the data context is now the selected plant, which does not have a plantlist property - so you are passing in an undefined property to your helper.

    Instead you need to get to the parent data and pass the plantlist property of the parent data object.

    There are many ways of doing that, see Accessing parent data. One way is to create a contextual parameter: ~plantlist=plantlist:

    {{for selectedplants itemVar="~plant" ~plantlist=plantlist}}
        Plant Code: {{:~plant}}<BR>
        Plant Name: {{:~plantNameFromCode(~plant, ~plantlist)}}<BR>
    {{/for}}
    

    Incidentally, you don't need to create the itemVar ~plant in this case, since the ~plant object is the current data context in the child view, which you can access directly as #data. So you could have simply written:

    {{for selectedplants ~plantlist=plantlist}}
        Plant Code: {{:#data}}<BR>
        Plant Name: {{:~plantNameFromCode(#data, ~plantlist)}}<BR>
    {{/for}}