Question

I've been searching and reading for a while now, and I'm just not grasping what I'm missing. I'm hoping you can help.

I've got a JSON data structure that contains two arrays: the first is a list of clients, and the second is a list of 'affected' clients:

var data = {
    allClients:      [ 
                       {clientId: 1, clientName: "Client One"},
                       {clientId: 2, clientName: "Client Two"},
                       {clientId: 3, clientName: "Client Three"},
                       {clientId: 4, clientName: "Client Four"},
                       {clientId: 5, clientName: "Client Five"},
                       {clientId: 6, clientName: "Client Six"},
                       {clientId: 7, clientName: "Client Seven"},
                       {clientId: 8, clientName: "Client Eight"}
                     ],
    clientsAffected: [ 1, 2, 5, 8 ]
};

I am using a simple jsRender template to create a select box, using the allClients array :

<script id="tmpl" type="text/x-jquery-tmpl">
  <select name="clients" id="clients" style="150px;" size=10 multiple>

{{for allClients}}
    <option value="{{:clientId}}">{{:clientId}} - {{:clientName}}</option>
{{/for}}

  </select>

</script>

This is working fine... produces a simple select box.

What I am trying to do (unsuccessfully) is to add a 'selected' attribute to the option that is rendered, so that in my example options 1, 2, 5, and 8 from clientsAffected are selected when the control is generated. I've been attempting to put another loop inside of the existing one, to iterate over the clientsAffected array and compare one value to the other, but I'm not having any success.

Has anyone done this before, or can you point me to a good document that describes what I need?

I've created a jsFiddle that represents what I have working: http://jsfiddle.net/LcSn7/17/

and one that is not that hopefully shows the direction I'm trying to go: http://jsfiddle.net/LcSn7/19/

Thanks in advance! -Tim

Was it helpful?

Solution

As an alternative to Jacob's suggestion, here is one approach, using a helper function. (In fact helper functions in effect allow conditionals to access more complex logic such as accessing loops etc.):

{{for allClients}}
    <option value="{{:clientId}}" {{:~isSelected(clientId)}}>
        {{:clientId}} - {{:clientName}}
    </option>
{{/for}}

with:

$("#container").html($("#tmpl").render(data, {isSelected: function(id) {
    return $.inArray(id, data.clientsAffected) > -1 ? 'selected="selected"' : ""
}}));

See updated version of your fiddle: http://jsfiddle.net/LcSn7/20/

You might also be interested in this, using JsViews: http://www.jsviews.com/#samples/tag-controls/multiselect

OTHER TIPS

You cannot with jsRender as-is, because it's conditionals lack the ability to check within loops or against other objects.

What you have is quite right, except for variable scoping; you need to scope within the {{for}} statement. See this question: "Access parent item inside a loop in jsrender".

But without equality conditional you need, you need to reorganize the data. Here's my suggestion, first add a boolean affected property to allClients, using the data you already have, like so:

for (var i = 0; i < data.allClients.length; i++){
    data.allClients[i].affected = (jQuery.inArray(data.allClients[i].clientId, data.clientsAffected) != -1);
}

Than from within your jsRender template, you can use simple truth conditionals:

<option value="{{:clientId}}" {{if affected}}selected="selected"{{/if}}>

My JSFiddle.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top