0

我创建了一个二维可排序容器的第一维(表中的行)和第二维(单元格在一行)。二维挖空排序不更新UI

单元格应该在行内拖动到现有行,以动态创建新行。空行应该动态删除。单元格被配置为占用一行中的所有空间。

如何编辑自定义敲除排序绑定(例如update事件)?

前:

Before

后:

After

更新问题:

  • 当拖动单元格(.sortable-cell) 新行(.sortable-table/.sortable-row)视图模型被更新,但不是UI
  • 占位符(.highlight-horizontal)不显示,中拖动单元格(.sortable-cell)时,一个新行(.sortable-table/.sortable-row

//connect items with observableArrays 
 
ko.bindingHandlers.sortableList = { 
 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
 
    $(element).data("sortList", valueAccessor().data); //attach meta-data 
 
    $(element).sortable({ 
 
     placeholder: valueAccessor().placeholder, 
 
     start: function(event, ui) {}, 
 
     change: function(event, ui) {}, 
 
     update: function(event, ui) { 
 
     var item = ui.item.data("sortItem"); 
 
     if (item) { 
 
      //identify parents 
 
      var originalParent = ui.item.data("parentList"); 
 
      var newParent = ui.item.parent().data("sortList"); 
 
      //identify viewModel 
 
      var viewModel = bindingContext.$root; 
 
      //figure out its new position 
 
      var position = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]); 
 

 
      if (ui.item.parent()[0].classList.contains("sortable-row")) { 
 
      //Row already exists 
 
      console.log("true"); 
 
      } else { 
 
      //Row doesn't exist, create new row (PROBLEM WITH UPDATE HERE) 
 
      newParent().splice(position, 0, { 
 
       "children": ko.observableArray([]) 
 
      }); 
 
      newParent = newParent()[position].children; 
 
      } 
 

 
      //Update item position 
 
      originalParent.remove(item); 
 
      newParent.splice(position, 0, item); 
 
      
 
      //Remove empty lists 
 
      var children = viewModel.children(); 
 
      for (var i = 0; i < children.length; i++) { 
 
      if (children[i].children().length == 0) { 
 
       viewModel.children.remove(children[i]); 
 
       console.log(children); 
 
      } 
 
      } 
 

 
      //Update UI 
 
      ui.item.remove(); 
 

 
      //Debug data model 
 
      console.log("final viewModel"); 
 
      var children = viewModel.children(); 
 
      for (var i = 0; i < children.length; i++) { 
 
      console.log(children[i].children()); 
 
      for (var j = 0; j < children[i].children().length; j++) { 
 
      \t console.log(children[i].children()[j].children(),children[i].children()[j].content()); 
 
      } 
 
      } 
 
     } 
 

 
     }, 
 
     connectWith: '.sortable-container' 
 
    }); 
 
    } 
 
}; 
 
//attach meta-data 
 
ko.bindingHandlers.sortableItem = { 
 
    init: function(element, valueAccessor) { 
 
    var options = valueAccessor(); 
 
    $(element).data("sortItem", options.item); 
 
    $(element).data("parentList", options.parentList); 
 
    } 
 
}; 
 
var self = this; 
 
var viewModel = function() { 
 
    var self = this; 
 
    self.children = ko.observableArray(
 
    [{ 
 
     "children": ko.observableArray([{ 
 
     "content": ko.observable("Item 1"), 
 
     "children": ko.observableArray([]) 
 
     }, { 
 
     "content": ko.observable("Item 2"), 
 
     "children": ko.observableArray([]) 
 
     }, { 
 
     "content": ko.observable("Item 3"), 
 
     "children": ko.observableArray([]) 
 
     }]) 
 
    }, { 
 
     "children": ko.observableArray([{ 
 
     "content": ko.observable("Item 4"), 
 
     "children": ko.observableArray([]) 
 
     }]) 
 
    }, { 
 
     "children": ko.observableArray([{ 
 
     "content": ko.observable("Item 5"), 
 
     "children": ko.observableArray([]) 
 
     }, { 
 
     "content": ko.observable("Item 6"), 
 
     "children": ko.observableArray([]) 
 
     }]) 
 
    }] 
 
); 
 
}; 
 
ko.applyBindings(new viewModel());
.sortable-table { 
 
    border: 1px red solid; 
 
    padding: 10px 0px; 
 
    list-style-type: none; 
 
    width: 100% !important; 
 
    display: table !important; 
 
} 
 
.sortable-table .sortable-row { 
 
    height: 100% !important; 
 
    display: table-row !important; 
 
    padding: 5px 0px; 
 
} 
 
.sortable-table .sortable-cell { 
 
    border: 1px solid green; 
 
    display: table-cell !important; 
 
    cursor: move; 
 
} 
 
.sortable-table .sortable-cell p { 
 
    display: inline; 
 
    margin: 0 !important; 
 
} 
 
.sortable-table .highlight-vertical { 
 
    width: 5px !important; 
 
    display: table-cell !important; 
 
    background-color: blue !important; 
 
} 
 
.sortable-table .highlight-horizontal { 
 
    height: 5px !important; 
 
    width: 100% !important; 
 
    display: block !important; 
 
    background-color: blue !important; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script> 
 
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script> 
 

 
<div class="sortable-container" data-bind="template: { name: 'rowTmpl', foreach: $data.children, templateOptions: { parentList: $data.children } }, sortableList: { data: $data.children, placeholder: 'highlight-horizontal' }"> 
 
</div> 
 

 
<script id="rowTmpl" type="text/html"> 
 
    <div class="sortable-table"> 
 
    <div class="sortable-row sortable-container" data-bind="template: { name: 'cellTmpl', foreach: $data.children, templateOptions: { parentList: $data.children } }, sortableList: { data: $data.children, placeholder: 'highlight-vertical' }"> 
 
    </div> 
 
    </div> 
 
</script> 
 

 
<script id="cellTmpl" type="text/html"> 
 
    <div class="sortable-cell" data-bind="sortableItem: { item: $data, parentList: $item.parentList }"> 
 
    <p data-bind="text: $data.content"></p> 
 
    </div> 
 
</script>

+2

作为* *一般规则,所述'的结合处理程序的init'部是用于处理需要在模型中得到反映视图的改变。 'update'部分用于处理模型中需要在视图中显示的更改。您没有“更新”部分,因此您的模型会更新,但是(如您所注)不是UI。 –

+0

当行被删除而没有任何特殊的UI更新时,它已经工作。它不能以相同的方式创建行。我的数据模型是正确的。 –

回答

0

问题出在线newParent.splice(position, 0, {"children": ko.observableArray([])});newParent被称为newParent(),这是造成这个问题。

//connect items with observableArrays 
 
ko.bindingHandlers.sortableList = { 
 
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { 
 
    $(element).data("sortList", valueAccessor().data); //attach meta-data 
 
    $(element).sortable({ 
 
     placeholder: valueAccessor().placeholder, 
 
     start: function(event, ui) {}, 
 
     change: function(event, ui) {}, 
 
     update: function(event, ui) { 
 
     var item = ui.item.data("sortItem"); 
 
     if (item) { 
 
      //identify parents 
 
      var originalParent = ui.item.data("parentList"); 
 
      var newParent = ui.item.parent().data("sortList"); 
 
      //identify viewModel 
 
      var viewModel = bindingContext.$root; 
 
      //figure out its new position 
 
      var position = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]); 
 

 
      if (ui.item.parent()[0].classList.contains("sortable-row")) { 
 
      //Row already exists 
 
      console.log("true"); 
 
      } else { 
 
      //Row doesn't exist, create new row (PROBLEM WITH UPDATE HERE) 
 
      newParent.splice(position, 0, { 
 
       "children": ko.observableArray([]) 
 
      }); 
 
      newParent = newParent()[position].children; 
 
      } 
 

 
      //Update item position 
 
      originalParent.remove(item); 
 
      newParent.splice(position, 0, item); 
 
      
 
      //Remove empty lists 
 
      var children = viewModel.children(); 
 
      for (var i = 0; i < children.length; i++) { 
 
      if (children[i].children().length == 0) { 
 
       viewModel.children.remove(children[i]); 
 
       console.log(children); 
 
      } 
 
      } 
 

 
      //Update UI 
 
      ui.item.remove(); 
 

 
      //Debug data model 
 
      console.log("final viewModel"); 
 
      var children = viewModel.children(); 
 
      for (var i = 0; i < children.length; i++) { 
 
      console.log(children[i].children()); 
 
      for (var j = 0; j < children[i].children().length; j++) { 
 
      \t console.log(children[i].children()[j].children(),children[i].children()[j].content()); 
 
      } 
 
      } 
 
     } 
 

 
     }, 
 
     connectWith: '.sortable-container' 
 
    }); 
 
    } 
 
}; 
 
//attach meta-data 
 
ko.bindingHandlers.sortableItem = { 
 
    init: function(element, valueAccessor) { 
 
    var options = valueAccessor(); 
 
    $(element).data("sortItem", options.item); 
 
    $(element).data("parentList", options.parentList); 
 
    } 
 
}; 
 
var self = this; 
 
var viewModel = function() { 
 
    var self = this; 
 
    self.children = ko.observableArray(
 
    [{ 
 
     "children": ko.observableArray([{ 
 
     "content": ko.observable("Item 1"), 
 
     "children": ko.observableArray([]) 
 
     }, { 
 
     "content": ko.observable("Item 2"), 
 
     "children": ko.observableArray([]) 
 
     }, { 
 
     "content": ko.observable("Item 3"), 
 
     "children": ko.observableArray([]) 
 
     }]) 
 
    }, { 
 
     "children": ko.observableArray([{ 
 
     "content": ko.observable("Item 4"), 
 
     "children": ko.observableArray([]) 
 
     }]) 
 
    }, { 
 
     "children": ko.observableArray([{ 
 
     "content": ko.observable("Item 5"), 
 
     "children": ko.observableArray([]) 
 
     }, { 
 
     "content": ko.observable("Item 6"), 
 
     "children": ko.observableArray([]) 
 
     }]) 
 
    }] 
 
); 
 
}; 
 
ko.applyBindings(new viewModel());
.sortable-table { 
 
    border: 1px red solid; 
 
    padding: 10px 0px; 
 
    list-style-type: none; 
 
    width: 100% !important; 
 
    display: table !important; 
 
} 
 
.sortable-table .sortable-row { 
 
    height: 100% !important; 
 
    display: table-row !important; 
 
    padding: 5px 0px; 
 
} 
 
.sortable-table .sortable-cell { 
 
    border: 1px solid green; 
 
    display: table-cell !important; 
 
    cursor: move; 
 
} 
 
.sortable-table .sortable-cell p { 
 
    display: inline; 
 
    margin: 0 !important; 
 
} 
 
.sortable-table .highlight-vertical { 
 
    width: 5px !important; 
 
    display: table-cell !important; 
 
    background-color: blue !important; 
 
} 
 
.sortable-table .highlight-horizontal { 
 
    height: 5px !important; 
 
    width: 100% !important; 
 
    display: block !important; 
 
    background-color: blue !important; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script> 
 
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script> 
 

 
<div class="sortable-container" data-bind="template: { name: 'rowTmpl', foreach: $data.children, templateOptions: { parentList: $data.children } }, sortableList: { data: $data.children, placeholder: 'highlight-horizontal' }"> 
 
</div> 
 

 
<script id="rowTmpl" type="text/html"> 
 
    <div class="sortable-table"> 
 
    <div class="sortable-row sortable-container" data-bind="template: { name: 'cellTmpl', foreach: $data.children, templateOptions: { parentList: $data.children } }, sortableList: { data: $data.children, placeholder: 'highlight-vertical' }"> 
 
    </div> 
 
    </div> 
 
</script> 
 

 
<script id="cellTmpl" type="text/html"> 
 
    <div class="sortable-cell" data-bind="sortableItem: { item: $data, parentList: $item.parentList }"> 
 
    <p data-bind="text: $data.content"></p> 
 
    </div> 
 
</script>