Assign Dynamic templates

馋奶兔 提交于 2019-12-25 04:53:11

问题


I am trying to use KnockoutJS to develop a wizard for my asp.net app.

This is my first attempt at using KO.

What I am trying to achieve is assign dynamic templates based on a Click event of an anchor tag.

My HTML looks like this

<script id="ParamHomeTmpl" type="text/html">
   <section class="alert alert-info">
       <div class="panel-heading h3  blackincolor"><i class="fa fa-exclamation-circle redincolor" style="margin-right: 5px"></i>Please Select Parameter Type</div>

       <ul class="blackincolor list-group">
           <li><a class="list-group-item list-group-item-info" data-bind="click: templateToUse" href="#" id="InputType"><b>Input Type:</b> Gives an Option to Select your Key-Value Pairs.</a></li>

           <li><a class="list-group-item list-group-item-success" data-bind="click: templateToUse" href="#" id="ListType"><b>List Type:</b> You can type in a Key and insert a list of values and select one of the values that you created.</a></li>
       </ul>
   </section>
</script>
<script id="InputTypeTmpl" type="text/html">
   <div>
       <p>Input Type</p>
   </div>
</script>
<script id="ListTypeTmpl" type="text/html">
   <div>
       <p>ListType</p>
   </div>
</script>
<script id="BlankTmpl" type="text/html">
   <div>
       <p>Blank</p>
   </div>
</script>
<div class="tab-pane" id="SelectParamType" data-bind="template: { name: templateToUse }">
</div>

And finally the actual JS is:

var viewModel = {
       currTemplate: function () {
        return "paramHome";
    },
    paramType: ko.observable("Metadata")
};

viewModel.secondStep = function (data, event) {

    // return (event.target.id);
    console.log(data);
};

viewModel.templateToUse = function (data, event) {
    try {
        alert(event.target.id);
        switch (event.target.id) {
            case "InputType":
                return "InputTypeTmpl";

            case "ListType":
                return "ListTypeTmpl";

            default:
                return "BlankTmpl";
        }
    }
    catch (err) { return "ParamHomeTmpl" ;}
};

ko.applyBindings(viewModel);

The issue is that when I click the anchor tag from the first step "Select Param Type", the template is not swapped automatically based on the click event target.

I am not sure what am I doing wrong here.

Jsfiddle: http://jsfiddle.net/sourabhtewari/c8tm1193/


回答1:


I know this is an old question, but I came across my previous answer and felt it needed to be fixed.

The main problem with your code is that you're using the function you've bound to the click as the template name. You should have a separate observable for the template name, and the function should set its value:

<div class="tab-pane" id="SelectParamType" data-bind="template: currTemplate">

...

var viewModel = {
  currTemplate: ko.observable('ParamHomeTmpl'),
  paramType: ko.observable("Metadata")
};

Also, you have no breaks in your switch, so it always falls through to default, though you fixed this in your answer.

A secondary problem is that clicking on the bold text in the link causes event.target to be the <b> element rather than the <a>, so you have no id. You can avoid this problem by binding the template name to the function call:

data-bind="click: templateToUse.bind($root, 'InputTypeTmpl')"

and using the data parameter in the function, which then becomes very simple:

viewModel.templateToUse = function(data) {
  viewModel.currTemplate(data);
};

In fact, you can do away with the function entirely and bind directly to the template name observable:

data-bind="click: currTemplate.bind($root, 'InputTypeTmpl')"

var viewModel = {
  currTemplate: ko.observable('ParamHomeTmpl'),
  paramType: ko.observable("Metadata")
};

viewModel.secondStep = function(data, event) {

  // return (event.target.id);
  console.log(data);
};

viewModel.templateToUse = function(data) {
  viewModel.currTemplate(data);
};

ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script id="ParamHomeTmpl" type="text/html">
  <section class="alert alert-info">
    <div class="panel-heading h3  blackincolor"><i class="fa fa-exclamation-circle redincolor" style="margin-right: 5px"></i>Please Select Parameter Type</div>

    <ul class="blackincolor list-group">
      <li><a class="list-group-item list-group-item-info" data-bind="click: currTemplate.bind($root, 'InputTypeTmpl')" href="#" id="InputType"><b>Input Type:</b> Gives an Option to Select your Key-Value Pairs.</a>
      </li>

      <li><a class="list-group-item list-group-item-success" data-bind="click: currTemplate.bind($root, 'ListTypeTmpl')" href="#" id="ListType"><b>List Type:</b> You can type in a Key and insert a list of values and select one of the values that you created.</a>
      </li>
    </ul>
  </section>
</script>
<script id="InputTypeTmpl" type="text/html">
  <div>
    <p>Input Type</p>
  </div>
</script>
<script id="ListTypeTmpl" type="text/html">
  <div>
    <p>ListType</p>
  </div>
</script>
<script id="BlankTmpl" type="text/html">
  <div>
    <p>Blank</p>
  </div>
</script>
<div class="tab-pane" id="SelectParamType" data-bind="template: currTemplate">
</div>



回答2:


I think your approach -- using templates -- is wrong. Dynamic HTML is what the if binding is for. The only legitimate use for templates (imo) is recursive HTML structure.

Update I no longer subscribe to this view. Templates are useful for recursive HTML and when a section of code may take several forms. Bind to a variable and update the variable with the proper template name. Original answer continues below.

I've made the click bindings set an observable that controls which section is displayed.

var viewModel = {
  section: ko.observable('blank'),
  paramType: ko.observable("Metadata")
};

viewModel.secondStep = function(data, event) {

  // return (event.target.id);
  console.log(data);
};

ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<section class="alert alert-info">
  <div class="panel-heading h3  blackincolor"><i class="fa fa-exclamation-circle redincolor" style="margin-right: 5px"></i>Please Select Parameter Type</div>

  <ul class="blackincolor list-group">
    <li><a class="list-group-item list-group-item-info" data-bind="click: section.bind(0, 'input')" href="#" id="InputType"><b>Input Type:</b> Gives an Option to Select your Key-Value Pairs.</a>
    </li>

   <li><a class="list-group-item list-group-item-success" data-bind="click: section.bind(0, 'list')" href="#" id="ListType"><b>List Type:</b> You can type in a Key and insert a list of values and select one of the values that you created.</a>
    </li>
  </ul>
</section>
<div data-bind="if:section()=='input'">
  <p>Input Type</p>
</div>
<div data-bind="if:section()=='list'">
  <p>ListType</p>
</div>
<div data-bind="if:section()=='blank'">
  <p>Blank</p>
</div>



回答3:


The problem is fixed using

applyBindingsToNode

Code:

viewModel.templateToUse = function(data, event) {
    try {

        switch (event.target.id) {

            case "InputType":
                templateType = "InputTypeTmpl";
                break;

            case "ListType":
                templateType = "ListTypeTmpl";
                break;

            case "FileType":
                templateType = "FileTypeTmpl";
                break;

            case "DataBaseType":
                templateType = "DataBaseTypeTmpl";
                break;

            default:
                return "BlankTmpl";

        }
    } catch (err) {
        return "BlankTmpl";
    }
    ko.applyBindingsToNode(document.getElementById("Attributes"), {
        template: {
            name: templateType
        }
    });

Fiddle: http://jsfiddle.net/sourabhtewari/c8tm1193/1



来源:https://stackoverflow.com/questions/31499059/assign-dynamic-templates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!