0

Я создаю двумерный сортируемый контейнер с первым измерением (строки в таблице) и вторым измерением (ячейки в строке).Двумерный нокаут сортируется, не обновляя UI

Клетки должны перетаскиваться в ряд, в существующие строки, в новые строки, созданные динамически. Пустые строки должны быть динамически удалены. Ячейки сконфигурированы так, чтобы занимать все пространство подряд.

Как отредактировать настраиваемое связывание Knockout (например, update)?

Перед:

Before

После того, как:

After

Проблемы с обновлением:

  • При перемещении ячейки (.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>

+2

В общем * * правило, 'init' участок связывания обработчика для обработки изменений представлений, которые должны быть отражены в модели. Раздел 'update' предназначен для обработки изменений в модели, которые должны отображаться в представлении. У вас нет раздела «update», поэтому ваша модель обновляется, но (как вы заметили), а не пользовательский интерфейс. –

+0

Он уже работает, когда строки удаляются без специального обновления пользовательского интерфейса. Для создания строк это не работает. Моя модель данных верна. –

ответ

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>

 Смежные вопросы

  • Нет связанных вопросов^_^