Я создаю двумерный сортируемый контейнер с первым измерением (строки в таблице) и вторым измерением (ячейки в строке).Двумерный нокаут сортируется, не обновляя UI
Клетки должны перетаскиваться в ряд, в существующие строки, в новые строки, созданные динамически. Пустые строки должны быть динамически удалены. Ячейки сконфигурированы так, чтобы занимать все пространство подряд.
Как отредактировать настраиваемое связывание Knockout (например, update
)?
Перед:
После того, как:
Проблемы с обновлением:
- При перемещении ячейки (
.sortable-cell
) на новую строку (.sortable-table
/.sortable-row
) модель представление обновляется, но не пользовательский интерфейс - не отображается Заполнитель (
.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>
В общем * * правило, 'init' участок связывания обработчика для обработки изменений представлений, которые должны быть отражены в модели. Раздел 'update' предназначен для обработки изменений в модели, которые должны отображаться в представлении. У вас нет раздела «update», поэтому ваша модель обновляется, но (как вы заметили), а не пользовательский интерфейс. –
Он уже работает, когда строки удаляются без специального обновления пользовательского интерфейса. Для создания строк это не работает. Моя модель данных верна. –