2015-11-15 47 views
0

我有一个可观察的项目数组。 “项目”的其中一个属性是“位置”,表示项目在列表中的位置。我希望能够通过在每个项目旁边放置位置下拉菜单来重新排序项目。当用户在下拉菜单中选择某个项目的位置时,将重新计算受影响项目的位置值。使用Knockout JS重新排列列表中的项目

我遇到的问题是当我尝试利用事件绑定下拉 - 我找不到一种方法将原来的新位置传递给我的'重新定位'功能。

我敢肯定,这可以通过使用数组索引这个简单的例子,但我想看看我能否避免这种情况。

的jsfiddle:http://jsfiddle.net/4tqahpkg/3/

<div class='liveExample'> 
<ul data-bind="foreach: orderedItems"> 
    <li> 
     <div> <span data-bind="text: name"> </span> has Position: 
      <select id="pos" data-bind=" options: orderedItems, 
        optionsText: function(item) { return item.position }, 
        optionsValue: function(item){ return item.position }, 
        value: position, 
        event: { change: function() {reposition($data.name(), position()); } } "></select> 
     </div> 
    </li> 
</ul> 

var Item = function (name, position) { 
    this.name = ko.observable(name); 
    this.position = ko.observable(position); 

} 

var viewModel = function() { 
    var self = this; 

    this.items = [ 
    new Item("item Three", "3"), 
    new Item("item One", "1"), 
    new Item("item Two", "2"), 
    new Item("item Five", "5"), 
    new Item("item Four", "4"), 
    new Item("item Six", "6")]; 


    self.orderedItems = ko.computed(function() { 

     return ko.utils.arrayFilter(this.items, function (item) { 
      return true; 
     }).sort(function (a, b) { 
      var value1 = "", 
       value2 = ""; 
      value1 = a.position() ? a.position() : ""; 
      value2 = b.position() ? b.position() : ""; 
      return value1 == value2 ? 0 : (value1 < value2 ? -1 : 1); 
     }); 
    }); 

    self.curName = ko.observable(); 

    self.curItem = ko.computed(function (name) { 
     return ko.utils.arrayFilter(this.items, function (item) { 
      return item.name() == self.curName(); 
     }); 
    }); 

    self.reposition = function (name, newPosition) { 

     self.curName(name); 
     origPosition = self.curItem()[0].position(); 

     if (origPosition < newPosition) { 
      for (var x = 0; x < orderedItems.length; x++) { 
       if (origPosition < newPosition && self.orderedItems()[x].position() >= origPosition && self.orderedItems()[x].position() < newPosition) { 
        self.orderedItems()[x].position(self.orderedItems()[x].position() - 1); 
       } 

       if (origPosition > newPosition && self.orderedItems()[x].position() >= newPosition && self.orderedItems()[x].position() < origPosition) { 
        self.orderedItems()[x].position(self.orderedItems()[x].position() + 1); 
       } 

       if (self.orderedItems().name() == name) { 
        self.orderedItems()[x].position(newPosition); 
       } 
      } 
     } 
    }; 


}; 

ko.applyBindings(viewModel); 
+1

太奇怪了...界面为什么不通过拖放使用列表重新排序和删除? –

+0

该列表可能包含数百个项目,可能难以拖放。这将是该行动的捷径。 – PaulP

回答

0

您要访问的老位置,但是你有没有为它定义任何存储。每个项目都必须有一个oldPosition变量(我已经创建了一个私有变量),并且在position上订阅了一个订阅,它在更新oldPosition之前调用您的reposition函数。

我已经对你的设计做了一些重新设计,我认为这有点复杂。我还没有实施reposition,我想你想转移其他项目的位置,所以你没有重复。

var viewModel = function() { 
 
    var self = this; 
 

 
    var Item = function(name, pos) { 
 
    this.name = ko.observable(name); 
 
    this.position = ko.observable(pos); 
 
    var oldPosition = pos; 
 
    this.position.subscribe(function(newValue) { 
 
     self.reposition(this, oldPosition, newValue); 
 
     oldPosition = newValue; 
 
    }, this); 
 
    }; 
 

 
    this.items = [ 
 
    new Item("item Three", "3"), 
 
    new Item("item One", "1"), 
 
    new Item("item Two", "2"), 
 
    new Item("item Five", "5"), 
 
    new Item("item Four", "4"), 
 
    new Item("item Six", "6") 
 
    ]; 
 

 

 
    self.orderedItems = ko.computed(function() { 
 
    return ko.utils.arrayFilter(this.items, function(item) { 
 
     return true; 
 
    }).sort(function(a, b) { 
 
     return a.position() - b.position(); 
 
    }); 
 
    }); 
 

 
    self.curName = ko.observable(); 
 

 
    self.reposition = function(item, oldPosition, newPosition) { 
 
    console.debug("Reposition", item, oldPosition, newPosition); 
 
    }; 
 

 
}; 
 

 
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> 
 
<div class='liveExample'> 
 
    <ul data-bind="foreach: orderedItems"> 
 
    <li> 
 
     <div> \t <span data-bind="text: name"> </span> has Position: 
 
     <select id="pos" data-bind=" options: orderedItems, 
 
\t \t \t \t \t \t optionsText: 'position', 
 
\t \t \t \t \t \t optionsValue: 'position', 
 
\t \t \t \t \t \t value: position "></select> 
 
     </div> 
 
    </li> 
 
    </ul> 
 
</div>

+0

谢谢罗伊。我的解决方案很尴尬,因为我认为当选择更改事件发生时,我将能够在用新的位置值更新之前读取旧的位置值。 – PaulP

+0

@PaulP还要注意,你不是在viewmodel构造函数上调用'new'。我没有明白。它会让事情变得不合时宜。 –

+0

谢谢罗伊 - 非常感谢! – PaulP