jsviews

JSViews syntax for converting value to select a template dynamically


In a jsviews based app, I have a data object that contains a type attribute (actually a server type).

I'd like to convert it and append a suffix to pass to a tmpl inclusion.

Let's say I have :

$.views.converters({
    "serverSideTypeToLocalType": function(serverSideType) {
        switch(serverSideType) {
            case "server-side-type1":
                return "type1";
            case "server-side-type2":
                return "type2";
            case "server-side-type3":
                return "type3";
            default:
                throw "Invalid type";
        }
    }
});

I also have templates :

<script type="text/x-jsrender" id"type1-edit">
template for editing type 1
</script>
<script type="text/x-jsrender" id"type1-view">
template for viewing type 1
</script><script type="text/x-jsrender" id"type2-edit">
template for editing type 2
</script>
<script type="text/x-jsrender" id"type2-view">
template for viewing type 2
</script><script type="text/x-jsrender" id"type3-edit">
template for editing type 3
</script>
<script type="text/x-jsrender" id"type3-view">
template for viewing type 3
</script>

My data object is :

var data = { MyObjects : [
{
    "ServerSideType": "server-side-type1",
    "IsEditing" : true
},{
    "ServerSideType": "server-side-type2",
    "IsEditing" : false
}] };

How to construct a main template that includes dynamically the correct template based on ServerSideType and IsEditing properties ?

I tried :

<div>
{^{for MyObjects}}


        {^{include ^tmpl=({serverSideTypeToLocalType:ServerSideType}+ "-" + IsEditing ? "edit":"view")/}}

{{/for}}

</div>

but it fails with a weird error Cannot read property 'bd' of undefined.

Here is a reproductible sample:

(function($) {
  $(function() {
    $.views.converters({
      "serverSideTypeToLocalType": function(serverSideType) {
        switch (serverSideType) {
          case "server-side-type1":
            return "type1";
          case "server-side-type2":
            return "type2";
          case "server-side-type3":
            return "type3";
          default:
            throw "Invalid type";
        }
      }
    });


    var data = {
      MyObjects: [{
        "ServerSideType": "server-side-type1",
        "IsEditing": true
      }, {
        "ServerSideType": "server-side-type2",
        "IsEditing": false
      }]
    };


    var tmpl = $.templates("#main");
    tmpl.link("#container", data);
  });

})(jQuery);
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>
<script type="text/x-jsrender" id="main">
  <div>
    {^{for MyObjects}} 
    <p>Object n° {^{:#index +1}}</p>
    
   {^{include ^tmpl=({serverSideTypeToLocalType:ServerSideType}+ "-" + IsEditing ? "edit":"view")/}}       

    {{/for}}

  </div>
</script>
<script type="text/x-jsrender" id="type1-edit">
  <div>
    template for editing type 1
  </div>
</script>
<script type="text/x-jsrender" id="type1-view">
  <div>
    template for viewing type 1
  </div>
</script>
<script type="text/x-jsrender" id="type2-edit">
  <div>
    template for editing type 2
  </div>
</script>
<script type="text/x-jsrender" id="type2-view">
  <div>
    template for viewing type 2
  </div>
</script>
<script type="text/x-jsrender" id="type3-edit">
  <div>
    template for editing type 3
  </div>
</script>
<script type="text/x-jsrender" id="type3-view">
  <div>
    template for viewing type 3
  </div>
</script>

<div id="container">Loading ...</div>


Solution

  • You can't nest a {:...} tag within the markup of a {{...}} tag.

    I would suggest using a helper, rather than a converter:

    {^{include ^tmpl="#" + ~serverToLocal(ServerSideType) + "-" + (IsEditing ? "edit":"view")/}}
    

    You can also use a data-linked element:

    <span data-link='{include ^tmpl="#" + ~serverToLocal(ServerSideType)+ "-" + (IsEditing ? "edit" : "view")}'></span>
    

    (function($) {
      $(function() {
        function serverToLocal(serverSideType) {
          switch (serverSideType) {
            case "server-side-type1":
              return "type1";
            case "server-side-type2":
              return "type2";
            case "server-side-type3":
              return "type3";
            default:
              throw "Invalid type";
          }
        }
    
        var data = {
          MyObjects: [{
            "ServerSideType": "server-side-type1",
            "IsEditing": true
          }, {
            "ServerSideType": "server-side-type2",
            "IsEditing": false
          }]
        };
    
        var tmpl = $.templates("#main");
        tmpl.link("#container", data, {serverToLocal: serverToLocal});
      });
    
    })(jQuery);
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jsviews/0.9.90/jsviews.min.js"></script>
    
    <script type="text/x-jsrender" id="main">
      <div>
    {^{for MyObjects}} 
      <p>Object n° {^{:#index +1}}</p>
      <input data-link="ServerSideType" />
      <input data-link="IsEditing" type="checkbox"/>
      {^{include ^tmpl="#" + ~serverToLocal(ServerSideType) + "-" + (IsEditing ? "edit":"view")/}}
    {{/for}}
      </div>
    
      Two:
      <div>
    {^{for MyObjects}} 
      <p>Object n° {^{:#index +1}}</p>
      <span data-link='{include ^tmpl="#" + ~serverToLocal(ServerSideType)+ "-" + (IsEditing ? "edit" : "view")}'></span>
    {{/for}}
      </div>
    </script>
    
    <script type="text/x-jsrender" id="type1-edit">
      <div>
    template for editing type 1
      </div>
    </script>
    <script type="text/x-jsrender" id="type1-view">
      <div>
    template for viewing type 1
      </div>
    </script>
    <script type="text/x-jsrender" id="type2-edit">
      <div>
    template for editing type 2
      </div>
    </script>
    <script type="text/x-jsrender" id="type2-view">
      <div>
    template for viewing type 2
      </div>
    </script>
    <script type="text/x-jsrender" id="type3-edit">
      <div>
    template for editing type 3
      </div>
    </script>
    <script type="text/x-jsrender" id="type3-view">
      <div>
    template for viewing type 3
      </div>
    </script>
    
    <div id="container">Loading ...</div>