Search code examples
jsrender

Loading different templates based on discriminator field in for loop


I am trying to load different templates in a for loop in a jsrender template.

I have tried different syntax but with no success. I have tried loading the template within a {{for fields tmpl="helperMethod()"}} and include within the loop as well. But no success till now.

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/1.0.5/jsrender.js"></script>
<script type="text/javascript" src="form.js"></script>
<title>Insert title here</title>
</head>
<body>
   <div id="formbody">      
   </div>
   <form name="submit()">
   <input name = "nitin" value="" placeholder="Put name">
   <input name = "password" value="" placeholder="Put password" type='password'>
   </form>

</body>
</html>

<script id="formTemplate" type="text/x-jsrender">
<form id={{:id}}>
    {{for steps tmpl="#stepTemplate"}}
    {{/for}}
</form>
</script>

<script id="stepTemplate" type="text/x-jsrender">
<div id={{:id}} data-order={{:order}}>
    <span><h2>{{:title}}</h2></span>
    <div id="dynamic-field-div">
        {{for fields tmpl="#"+~loadTemplate(:mytype)/}}
    </div>
</div>
</script>

<script id="field-input-template" type="text/x-jsrender">
<span>{{:type}}</span>
<span>{{:templateOptions.label}}</span>
<input name = {{:key}} id={{:id}} field-order={{:#index}} {{if templateOptions.hint != null && templateOptions.hint != "" }} placeHolder={{:templateOptions.hint}} {{/if}}>
</script>

<script id="field-password-template" type="text/x-jsrender">
<span>{{:label}}</span>
<input name = {{:key}} id={{:id}} field-order={{:#index}} type="password">
</script>
$(document).ready(function(){
    var formDescription = {
              "id":"loginForm",
              "steps": [
                    {
                      "id": "step_0",
                      "order": 0,
                      "title": "Personal Details",
                      "fields": [
                        {
                          "key": "firstName",
                          "templateOptions": {
                            "label": "First Name",
                            "hint": "enter first name"
                          },
                          "mytype":"input"
                        },
                        {
                          "key": "lastName",
                          "templateOptions": {
                            "label": "Last Name"

                          },
                          "mytype":"password"
                        }
                      ]
                    },
                    {
                      "id": "step_1",
                      "order": 1,
                      "title": "Business Details",
                      "fields": [
                        {
                          "key": "email",
                          "templateOptions": {
                            "label": "First Name",
                            "hint": "input first name"
                          },
                          "mytype":"input"
                        },
                        {
                          "key": "mobile",
                          "templateOptions": {
                            "label": "Last Name",
                            "hint": "input last name"
                          },
                          "mytype":"password"
                        }
                      ]
                    }
                  ]
                };


    var templateObjects = $.templates({
          stepTmpl: "#stepTemplate",
          formTmpl: "#formTemplate"
        });

    function loadTemplateFromType(type) {
        console.log(type);
        return "field-"+type+"-template";
    }
    var myHelpers = {"loadTemplate": loadTemplateFromType};
    $.views.helpers(myHelpers);


    function appendToDom() {
        $('#formbody').append(generateFormHTML());
    }

    function generateFormHTML() {
        console.log("in generate");
        var formHtml = $.render.formTmpl(formDescription);
        return formHtml;
    }

    appendToDom();

});

This is the error message that I can see on console.

message
:
"Syntax error↵Compiled template code:↵↵// stepTmpl↵var v,t=j._tag,ret=""↵+"\n<div id=";↵try{↵ret+=((v=data.id)!=null?v:"");↵}catch(e){ret+=j._err(e,view,undefined);}ret=ret↵+" data-order=";↵try{↵ret+=((v=data.order)!=null?v:"");↵}catch(e){ret+=j._err(e,view,undefined);}ret=ret↵+">\n <span><h2>";↵try{↵ret+=((v=data.title)!=null?v:"");↵}catch(e){ret+=j._err(e,view,undefined);}ret=ret↵+"</h2></span>\n    <div id=\"dynamic-field-div\">\n       ";↵try{↵ret+=t("for",view,this,[↵{view:view,content:false,tmpl:false,↵  params:{args:['fields'],↵   props:{'tmpl':'\"#\"+~loadTemplate(:mytype)'}},↵    args:[data.fields],↵    props:{'tmpl':"#"+view.ctxPrm("loadTemplate")(:data.mytype)}}]);↵}catch(e){ret+=j._err(e,view,undefined);}ret=ret↵+"\n    </div>\n</div>\n";↵return ret;↵: "Unexpected token :""
name:"JsRender Error"
}

The for loop in the "stepTemplate" in the index.html in the contentious code. If I remove the ":" from the ":mytype" then it just prints the expression in the browser .


Solution

  • The problem is with

    {{for fields tmpl="#"+~loadTemplate(mytype)/}}
    

    which will use the template returned by ~loadTemplate(mytype), and iterate over the fields using that template. You want to iterate over the fields, and use a different template for each field, based on the mytype value on the field object.

    You can do it like this:

    {{for fields}}{{include tmpl="#"+~loadTemplate(mytype)/}}{{/for}}