Search code examples
jsviews

Select a complex object in a drop down list and get additional data


I use jsViews to build an application.

At some place, I have an array of complex objects. The array is bound in a dropdown list where I can set the label and the value to properties of my object.

However, I have to get also some other properties of my custom object.

How can I do that?

Right now I have :

(function($) {
  var dataVm = {
    value: null,
    choices: [
      { "label" : "France", "value" : "FR", "icon" : "flag-icon-fr" },
      { "label" : "Germany", "value" : "DE", "icon" : "flag-icon-de" },
      { "label" : "Brazil", "value" : "BR", "icon" : "flag-icon-br" },
      { "label" : "USA", "value" : "US", "icon" : "flag-icon-us" }
    ],
    icon: "flag-icon-fr"
  };

  var helpers = {
    doSelect : function(){
      // Fake business rule, I.E. call a web service to get country data
      var valueFromBusinessLogic = "FR"; 
      $.observable(dataVm).setProperty("value", valueFromBusinessLogic);
    }
  };

  $.templates("#mainTemplate").link("#container", dataVm, helpers);
})(jQuery);
<link href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/css/flag-icon.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>


<script id="mainTemplate" type="text/x-jsrender">
  <p>Selected : <span>{^{:value}}</span></p>
  <p>Flag  : <span data-link="class{:('flag-icon ' + icon)}"></span></p>
  <select data-link='value'>
	{^{for choices}}
   <option value="{{:value}}">{{:label}}</option>
  {{/for}}
	</select>

  <button data-link="{on ~doSelect}">Select from business logic</button>
</script>

<div id="container">

</div>

This is working as expected, but I can't get the icon sub property.

My value property is important and may be set from external actions (form init or button click). So I can't (at least I believe), I can't play with #index because it would put the index in the value property.


Solution

  • You need to decide what your selected country property is - it can be the object, the index in the choices array, or the value string. But the default binding of the select is the value.

    If you keep the value string as selected country, then you can define a lookup helper to return the object:

    function countryFromVal(val) {
      var i = dataVm.choices.length;
      while (i--) {
        if (dataVm.choices[i].value === val) {
          return dataVm.choices[i];
        }
      }
      return dataVm.choices[0];
    }
    
    var helpers = {
        countryFromVal: countryFromVal,
    

    and write

    <span data-link="class{:('flag-icon ' + ~countryFromVal(value).icon)}"></span>
    

    Alternatively you can make the selected country property be the index, and use converters on the select like in this sample: http://www.jsviews.com/#link-select@selectconvert.

    Or you can make it be the object itself, again using converters, like this:

    (function($) {
      var dataVm = {
        choices: [
          { "label" : "France", "value" : "FR", "icon" : "flag-icon-fr" },
          { "label" : "Germany", "value" : "DE", "icon" : "flag-icon-de" },
          { "label" : "Brazil", "value" : "BR", "icon" : "flag-icon-br" },
          { "label" : "USA", "value" : "US", "icon" : "flag-icon-us" }
        ]
      };
    
      dataVm.country = dataVm.choices[1];
    
      function countryFromVal(val) {
        var i = dataVm.choices.length;
        while (i--) {
          if (dataVm.choices[i].value === val) {
            return dataVm.choices[i];
          }
        }
        return dataVm.choices[0];
      }
    
      function valFromCountry(country) {
        return country.value;
      }
    
      $.views.converters({
        fromValue: countryFromVal,
        toValue: valFromCountry
      });
    
      var helpers = {
        doSelect : function(){
          // Fake business rule, I.E. call a web service to get country data
          var valueFromBusinessLogic = "FR"; 
          $.observable(dataVm).setProperty("country", countryFromVal(valueFromBusinessLogic));
        }
      };
    
      $.templates("#mainTemplate").link("#container", dataVm, helpers);
    })(jQuery);
    <link href="https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/css/flag-icon.min.css" rel="stylesheet"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>
    
    <script id="mainTemplate" type="text/x-jsrender">
      <p>Selected : <span>{^{:country^value}}</span></p>
      <p>Flag  : <span data-link="class{:'flag-icon ' + country^icon}"></span></p>
    
      <select data-link='{toValue:country:fromValue}'>
        {^{for choices}}
          <option value="{{:value}}">{{:label}}</option>
        {{/for}}
      </select>
    
      <button data-link="{on ~doSelect}">Select from business logic</button>
    </script>
    
    <div id="container"></div>

    Note the syntax country^icon - see http://www.jsviews.com/#linked-paths@deep