如何在knockoutjs中绑定点击处理程序到模板,而不需要全局视图模型

How to bind click handlers to templates in knockoutjs without having a global viewModel?

本文关键字:不需要 模型 视图 全局 程序 knockoutjs 绑定 处理      更新时间:2023-09-26

我对KnockoutJs很陌生,所以我希望有一个众所周知的最佳实践来解决这种情况,我只是没能找到。

我有一个包含项目数组的视图模型。我想使用模板显示这些项目。我还希望每个项目能够在视图和编辑模式之间切换。我认为最适合Knockout的是在主视图模型上或(可能更好)在数组中的每个项目上创建相关函数,然后在模板中绑定此函数。因此,我在我的页面上创建了以下代码:

<ul data-bind="template: {name: testTemplate, foreach: items}"></ul>
<script id="testTemplate" type="text/x-jquery-tmpl">
  <li>
    <img src="icon.png" data-bind="click: displayEditView"  />
    <span data-bind="text: GBPAmount"></span>
    <input type="text" data-bind="value: GBPAmount" />
  </li>
</script>
<script>
(function() {
  var viewModel = new TestViewModel(myItems);
  ko.applyBindings(viewModel);
})();
</script>

在一个单独的文件中:

function TestViewModel(itemsJson) {
  this.items = ko.mapping.fromJS(itemsJson);
  for(i = 0; i < this.items.length; ++i) {
    this.items[i].displayEditView = function () {
      alert("payment function called");
    }
  }
  this.displayEditView = function () {
    alert("viewmodel function called");
  }
};

由于环境我的JS运行在我不能添加任何到全局命名空间,因此匿名函数来创建和设置视图模型。(如果有必要,我可以在一个名称空间中添加东西。)这个限制似乎打破了我发现的所有示例,这些示例似乎依赖于全局viewModel变量。

注:如果有一种方法比我想做的更适合knockoutJS,请随时提出建议!

当您的viewModel无法全局访问时,有几个选项。

首先,您可以使用templateOptions参数将任何相关方法传递给模板绑定。

它看起来像(也要注意静态模板名应该带引号):

data-bind="template: {name: 'testTemplate', foreach: items, templateOptions: { vmMethod: methodFromMainViewModel } }"

则在模板内部,vmMethod将作为$item.vmMethod可用。如果您使用templateOptions作为最后一个参数,那么请确保在括号之间有一个空格,{ {或jQuery模板会尝试将其解析为自己的。

你可以这样绑定它:

<img src="icon.png" data-bind="click: $item.vmMethod"  />

另一种选择是在每个项上放置一个方法和对视图模型中任何相关内容的引用。看起来你正在探索这个选项。

最后,在KO 1.3中(希望在9月发布并很快进入测试版)将有一个很好的方法来使用jQuery的live/delegate功能并将其与viewModel连接(如本示例:http://jsfiddle.net/rniemeyer/5wAYY/)

另外,这篇文章的"在事件绑定中避免匿名函数"一节也可能对你有所帮助。如果您正在寻找使用动态选择的模板进行就地编辑的示例,那么这篇文章可能会有所帮助。

这是为那些询问如何将变量methods(函数)传递给Knockout Template的人准备的。template的核心特性之一是使用可变数据,它可以是Stringfunction。在KO中,这些变量可以嵌入到dataforeach属性中,以便模板呈现。嵌入在dataforeach中的对象,无论是String, function等,都可以使用$data在此上下文中访问。

您可以查看这段代码,看看它是否可以帮助您将函数传递给Knockout Template。

function ViewModel() {
 this.employees = [
     { fullName: 'Franklin Obi', url: 'employee_Franklin_Obi', action: methodOne },
     { fullName: 'John Amadi', url: 'employee_John_Amadi', action: methodTwo }
 ],
this.methodOne = function(){ alert('I can see you'); },
this.methodTwo = function(){ alert('I can touch you'); }
}
ko.applyBindings(new ViewModel());

<ul  data-bind="template: { name: employeeTemplate, foreach: employees }" ></ul>
     <script type="text/html" id="employeeTemplate">
         <li><a data-bind="attr: { href: '#/'+url }, text: fullName, click: $data.action"></a></li>
    </script>

如果你想服务多个模板结构,你可以像这样在你的ViewModel中引入一个switch方法,并使用as属性为每个项目(雇员)引入别名。确保将开关键linkable添加到项目对象中。

...
this.employees = [
     { fullName: 'Franklin Obi',  linkable : false },
     { fullName: 'John Amadi', url: 'employee_John_Amadi', action: methodTwo, linkable : true }
 ],
this.methodLinkTemplate = function(employee){return employee.linkable ? "link" : "noLink"; } //this is a two way switch, many way switch is applicable.
...

则模板表单的id将被命名为;

<ul  data-bind="template: { name: employeeTemplate, foreach: employees, as: 'employee' }" ></ul>
  <script type="text/html" id="noLink">
     <li data-bind="text: fullName"></li>
  </script>
  <script type="text/html" id="link">
     <li><a data-bind="attr: { href: '#/'+url }, text: fullName, click: $data.action"></a></li>
  </script>

我没有运行过这个代码,但我相信这个想法可以节省一些人的时间。