KnockoutJS:如何在单击绑定列表项

时间:2015-07-05 22:23:53

标签: knockout.js

如果单击绑定的html列表项,如何获取对根视图模型的引用?

我有一个ViewModel闭包“class”,它使用KnockoutJS进行绑定。

ViewModel保存一个ko.observableArray,表示无序列表中的每个列表项。

// ViewModel Base
var ViewModel=( function(){

    // ctor
    function ViewModel(data,id){
        // Publics
        this.list=ko.observableArray([{name:'one'},{name:'two'},{name:'three'}]);
        this.selectedItem=ko.observable(null);
    };

    // set "selectedItem" when user clicks an <li>
    ViewModel.prototype.selectItem=function(){

        // below works when using instantiated "vm1"
        vm1.selectedItem(this);

        // correctly reports the name property of the clicked list item
        console.log(vm1.selectedItem().name);
    };

    // Return Publics
    return(ViewModel);

})();

// Build a new view model
var vm1=new ViewModel();

// apply bindings
ko.applyBindings(vm1);

observableArray绑定到Html无序列表。

单击列表项时,每个html列表项在ViewModel中触发.selectItem

<ul data-bind='foreach:list'>
    <li class='item' data-bind='click: $root.selectItem' >
        <span data-bind='text:name'></span>
    </li>
</ul>

问题是......

.selectItem中,我需要在视图模型实例上设置selectedItem属性。

但我没有办法从KnockoutJS提供给this的{​​{1}}获取视图模型实例。

直接使用selectedItem实例,但我不希望我的通用ViewModel使用对vm1

的硬编码引用
vm1

段:

    // set "selectedItem" when user clicks an <li>
    ViewModel.prototype.selectItem=function(){

        // below fails when using "ViewModel" (and numerous other tries by me)
        ViewModel.selectedItem(this);  // error 

        console.log(vm1.selectedItem().name);
    };
function log(){console.log.apply(console,arguments);}


// ViewModel Base
var ViewModel=( function(){

  // ctor
  function ViewModel(data,id){
    // Publics
    this.list=ko.observableArray([{name:'one'},{name:'two'},{name:'three'}]);
    this.selectedItem=ko.observable(null);
  };

  // set "selectedItem" when user clicks an <li>
  ViewModel.prototype.selectItem=function(){
    // below works when using specified vm1
    // below fails when using ViewModel.selectedItem(this)
    vm1.selectedItem(this);
    alert('Clicked on: '+vm1.selectedItem().name);
  };

  // Return Publics
  return(ViewModel);

})();

// Build a new view model
var vm1=new ViewModel();

// apply bindings
ko.applyBindings(vm1);

2 个答案:

答案 0 :(得分:3)

The recommended way of writing methods in your viewmodels是在构造函数中定义它们,而不是在原型中定义它们,因此它们对构造的视图模型进行操作:

function ViewModel(data,id){
  var that = this;
  // Publics
  this.list = ko.observableArray([{name:'one'},{name:'two'},{name:'three'}]);
  this.selectedItem = ko.observable(null);

  this.selectItem = function(item){
    that.selectedItem(item);
    alert('Clicked on: '+that.selectedItem().name);
  };

}

此外,您应该使用$parent上下文,而不是$root,因此它甚至可以在另一个视图模型中使用:

<ul data-bind='foreach:list'>
  <li class='item' data-bind='click: $parent.selectItem'>
    <span data-bind='text:name'></span>
  </li>
</ul>

答案 1 :(得分:0)

我通过这种方式获得视图模型参考,而无需在视图模型中对视图模型实例进行硬编码&#34; class&#34;。

它涉及抓取浏览器的事件对象并使用它来获取ViewModel SELECT p.username, pcm.status FROM Profile p LEFT JOIN p.mappings pcm WHERE pcm.club.id = 480 $root

虽然这有效,但我认为必须有一种更简单的方法来消除通用ViewModel中的硬编码引用。

还有其他想法吗?

ko.contextFor(event.target).$root

&#13;
&#13;
// set "selectedItem" when user clicks an <li>
ViewModel.prototype.selectItem=function(item,event){

    // get a reference to the view model using ko.contextFor
    var theVM=ko.contextFor(event.target).$root;

    // set the "selectedItem" property on the view model
    theVM.selectedItem(this);

     // working!
    alert(vm1.selectedItem().name); 
};
&#13;
// ViewModel Base
var ViewModel=( function(){

  // ctor
  function ViewModel(data,id){
    // Publics
    this.list=ko.observableArray([{name:'one'},{name:'two'},{name:'three'}]);
    this.selectedItem=ko.observable(null);
  };

  // set "selectedItem" when user clicks an <li>
  ViewModel.prototype.selectItem=function(item,event){
    var theVM=ko.contextFor(event.target).$root;
    theVM.selectedItem(this);
    // It works!
    alert(vm1.selectedItem().name);
  };

  // Return Publics
  return(ViewModel);

})();

// Build a new view model
var vm1=new ViewModel();

// apply bindings
ko.applyBindings(vm1);
&#13;
&#13;
&#13;