动态行创建淘汰赛

时间:2013-02-27 06:40:56

标签: javascript arrays knockout.js foreach

使用knockout js我正在尝试创建一个具有4个和4个coulmns的表。下面是我的数组,它将有16个元素需要放在表格中。

    /*----------------------------------------------------------------------*/
/* View Model                                                           */
/*----------------------------------------------------------------------*/
function ViewModel() {
    var self = this;
    self.items = ko.observableArray(["1.jpg", 
                                      "2.jpg", 
                                      "3.jpg", 
                                      "4.jpg",
                                      "5.jpg",
                                      "6.jpg"
                                      ]);
    self.itemRows = ko.computed(function () { //computes the rows dynamically based on items
        var rows = [];
        var count = 0;
        var items = self.items(); //get the item array
        var current = [];
        for(var i in items)
        {
            var item = items[i];
            current.push(item);
            count++;

            if (count == 4)
            {
                count = 0;
                rows.push(current);
                current = []; //next array
            }
        }

        if (current.length > 0)
        {
            rows.push(current);
        }

        return rows;
    });

    self.bindSort = function() {

        var startIndex = -1;         
        var sortableSetup = {        
         start: function (event, ui)
         {         
          startIndex = ui.item.index();
         },


         stop: function (event, ui) 
         {      
          var newIndex = ui.item.index();        
          if (startIndex > -1) 
          {
              self.from = ko.observable(startIndex);
              self.to = ko.observable(newIndex);
              var iTo = parseInt(self.to());
          var iFrom = parseInt(self.from());
          var from = self.items()[iFrom];
              var to = self.items()[iTo];
              self.items()[iTo] = from;
                  self.items()[iFrom] = to;
                  //alert('before');
                  // alert(from);
                  // alert(to);
                  var fromA = self.items()[iFrom];
              var toA = self.items()[iTo]; 
              //alert('after');
          //alert(fromA);
                  // alert(toA);
              self.items.remove(from);               
              self.items.splice(newIndex, 0, toA);
               self.items.remove(to); 
                self.items.splice(startIndex, 0, fromA);
                          //ui.item.remove();
               self.items.valueHasMutated();

          }

         }
        };


        $(".fruitList").sortable( sortableSetup );                           

    };

}   

/*----------------------------------------------------------------------*/
/* KO HTML Binding                                                      */
/*----------------------------------------------------------------------*/   
$(document).ready(function() {

    // create the view model
    var model = new ViewModel();

    // call the bind method for jquery UI setup
    model.bindSort();

    // binds ko attributes with the html
    ko.applyBindings(model);

});

并尝试在html中执行此操作,

<table data-bind="foreach: itemRows">
              <tr class="fruitList" data-bind="foreach: $data">
                  <td><img data-bind="attr: { src: $data }" /></td>
              </tr>
        </table>

我无法获得数组的长度以及如何在第一次创建4个tds然后创建第二行时打破循环..任何建议???

更新

当我使用sortable时,下面的代码似乎不起作用,

    start: function (event, ui)
     {         
      startIndex = ui.item.index();
     },


     stop: function (event, ui) 
     {      
      var newIndex = ui.item.index();  

1 个答案:

答案 0 :(得分:2)

更新:移至可排序版本的底部

不可排序的版本

在编辑和提及排序之前,我创建了一个似乎符合您要求的jsfiddle:http://jsfiddle.net/fENSD/4/

我所做的是创建一个计算的observable,它观察你的项目是否可观察,并返回一个嵌套数组,其形状是你想要表格渲染的形状。这不是最有效的功能,但是通过一些工作,你可以减少分配的数组的数量(此时,每次更新时将为4x4网格创建5个左右):

self.items = ko.observableArray(["images/1.jpg", "images/2.jpg", "images/3.jpg", "images/4.jpg", "images/5.jpg", "images/6.jpg"]);

self.itemRows = ko.computed(function () { //computes the rows dynamically based on items
    var rows = [];
    var count = 0;
    var items = self.items(); //get the item array
    var current = [];
    for(var i in items)
    {
        var item = items[i];
        current.push(item);
        count++;

        if (count == 4)
        {
            count = 0;
            rows.push(current);
            current = []; //next array
        }
    }

    if (current.length > 0)
    {
        rows.push(current);
    }

    return rows;
});

然后表格呈现如下:

<table data-bind="foreach: itemRows">
    <tr data-bind="foreach: $data">
        <td><img data-bind="attr: { src: $data }" /></td>
    </tr>
</table>

JSFiddle包含一个向可观察项目添加项目的示例,以及正在更新的表格,以便反映出您是否希望在行动中看到该项目。在JSFiddle中还有一个示例,您可以通过一种方式获取items数组的长度(data-bind="text: items().length")。

可排序版本

这是一个相当大的变化,但我设法让排序工作。以jquery ui网站为例,我得到了以下内容:

http://jsfiddle.net/fENSD/11/

对表进行排序非常困难,因此jquery ui示例实际上使用了一个列表,该列表具有定义的宽度,每个元素占用一定的宽度。这有效地创建了一个表。我假设你使用的图像可以使它们的大小完全相同。

要做到这一点,我有一些像这样的CSS:

#items { list-style-type: none; margin: 0; padding: 0; width: 200px; }
#items li { width: 48px; margin: 0px; padding: 0px; float: left; text-align: center; height: 48px; }

然后我创建了一个适当的绑定处理程序,如下所示:

ko.bindingHandlers['sortable'] = {
    init: function (element, valueAccessor) {
        var $element = $(element);
        var observable = valueAccessor();
        var value = ko.utils.unwrapObservable(observable);
        $element.sortable({
            stop: function(event, ui) {
                var prev = ui.item.prev();
                var data = ko.dataFor(ui.item[0]);
                var index = 0;
                if (prev.length > 0) {
                    //not the first item
                    var prevData = ko.dataFor(prev[0]);
                    var index = value.indexOf(prevData) + 1;
                }
                var oldIndex = value.indexOf(data);
                value.splice(oldIndex, 1);
                value.splice(index, 0, data);
                observable.valueHasMutated();
            }
        });
    }
};

每当更新sortable时,它都会修改传递给绑定的可观察数组。 注意:这是非常不可靠的,需要检查以确保传递的值实际上是一个可观察的值,然后再告诉它其值已经发生变异。

viewmodel看起来像这样:

function ViewModel() {
    var self = this;

    self.items = ko.observableArray(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13"]);

    self.items.subscribe(function (value) {
        console.log(value); //this is so you can see that the array is indeed being re-sorted
    });

    self.add = function () {
        self.items.push("another thing");
    };
}

并呈现:

<ul id="items" data-bind="sortable: items, foreach: items">
    <li><img data-bind="attr: { src: $data }" /></li>
</ul>

此方法的局限性在于,如果您的项目大小不同,则可排序的顺序与内存中实际表示的顺序略有不同。但是,假设您的所有元素大小相同,它应该可以正常工作。另一个问题是,这对重复项目不起作用。但是,要解决这个问题,应该是将每个元素作为包含值(甚至可以是可观察值)的对象而不是普通旧字符串的简单问题。