从knockout observablearray删除新项目不更新kendo sortable

时间:2014-09-25 16:33:25

标签: knockout.js kendo-ui

我正在尝试创建一种简单的方法来定义组列表。这些组包括id,描述,启用/禁用字段和排序顺序。我正在尝试使用KendoUI可排序小部件。我遇到的问题是:

  1. 添加新项目
  2. 在列表中向上移动项目
  3. 尝试从列表中删除该项
  4. 该项目将从可观察数组中删除,但仍会显示在可排序的小部件中。

    我试图尽可能地简化代码以证明问题。

    & #13;
    
    //--------------------------------------------------------------------------------------------------
    // MenuGroup View Models
    //--------------------------------------------------------------------------------------------------
    function MenuGroup() {
      var self = this;
      self.MenuGroupId = ko.observable(0);
      self.Description = ko.observable("");
      self.DisplayOrder = ko.observable(0);
      self.MenuActive = ko.observable(true);
    }
    
    var menuGroupMapping = {
      MenuGroup: {
        key: function(group) {
          return ko.utils.unwrapObservable(group.MenuGroupId);
        },
        create: function(group) {
          var groupObj = ko.mapping.fromJS(group);
          return groupObj;
        }
      }
    }
    
    function MenuGroupsViewModel() {
      var self = this;
    
      self.baseUri = "/api/menugroups";
      self.menugroups = ko.observableArray();
      self.newMenuGroup = ko.observable(new MenuGroup());
      self.selectedGroup = ko.observable(new MenuGroup());
    
      self.save = function(formElement) {
        self.newMenuGroup().DisplayOrder(self.menugroups().length);
        self.menugroups.push(self.newMenuGroup());
        var g = new MenuGroup();
        self.newMenuGroup(g);
      };
    
      self.deleteGroup = function(group) {
        bootbox.confirm("Are you sure you want to delete the following menu group: " + group.Description(), function(result) {
          self.menugroups.remove(group);
        });
      }
    
      self.selectGroup = function(group) {
        self.selectedGroup(group);
      };
    
      self.changeOrder = function(oldPosition, newPosition) {
        var movedGroup = self.menugroups()[oldPosition];
        movedGroup.DisplayOrder(newPosition);
        var id = movedGroup.MenuGroupId();
    
        ko.utils.arrayForEach(self.menugroups(), function(menugroup) {
          if (oldPosition < newPosition) {
            if (oldPosition <= menugroup.DisplayOrder() && newPosition >= menugroup.DisplayOrder() && menugroup.MenuGroupId() != id) {
              menugroup.DisplayOrder(menugroup.DisplayOrder() - 1);
            }
          } else {
            if (oldPosition >= menugroup.DisplayOrder() && newPosition <= menugroup.DisplayOrder() && menugroup.MenuGroupId() != id) {
              menugroup.DisplayOrder(menugroup.DisplayOrder() + 1);
            }
          }
        });
    
        self.menugroups().splice(oldPosition, 1);
        self.menugroups().splice(newPosition, 0, movedGroup);
      }
    
      var data = [{
        "MenuGroupId": 0,
        "Description": "Group A",
        "DisplayOrder": 0,
        "MenuActive": true
      }, {
        "MenuGroupId": 1,
        "Description": "Group B",
        "DisplayOrder": 1,
        "MenuActive": false
      }, {
        "MenuGroupId": 2,
        "Description": "Group C",
        "DisplayOrder": 2,
        "MenuActive": true
      }, {
        "MenuGroupId": 3,
        "Description": "Group D",
        "DisplayOrder": 3,
        "MenuActive": true
      }]
      ko.mapping.fromJS(data, menuGroupMapping, self.menugroups);
    }
    
    
    //--------------------------------------------------------------------------------------------------
    // Custom Bindings
    //--------------------------------------------------------------------------------------------------
    ko.bindingHandlers.showModal = {
      init: function(element, valueAccessor) {},
      update: function(element, valueAccessor) {
        var value = valueAccessor();
        if (ko.utils.unwrapObservable(value)) {
          $(element).modal('show');
          $("input", element).focus();
        } else {
          $(element).modal('hide');
        }
      }
    }
    
    
    
    mg = new MenuGroupsViewModel();
    
    ko.applyBindings(mg, document.getElementById('menu-group-panel'));
    
    
    $(document).ready(function() {
      $("#menu-list").kendoSortable({
        handler: ".menu-group-handle",
        hint: function(element) {
          return element.clone().addClass("hint");
        },
        placeholder: function(element) {
          return element.clone().css({
            "opacity": 0.3,
            "border": "1px dashed #000000"
          });
        },
        axis: "y",
        container: "#menu-list",
        cursor: "move",
        change: onChange
      });
    });
    
    function onChange(e) {
      mg.changeOrder(e.oldIndex, e.newIndex);
    }
    &#13;
    body {
      padding: 20px;
    }
    .def-panel {
      height: 100%;
      margin: 0 30px 0 0;
      width: 300px;
      float: left;
    }
    #menu-list {
      padding: 0;
      width: 200px;
    }
    .menu-group-handle {
      width: 30px;
      height: 50px;
      display: inline-block;
      background-color: darkslategray;
    }
    div.menu-group {
      display: inline-block;
      width: 200px;
      height: 50px;
      background-color: aliceblue;
      font-family: "Segoe Ui", Helvetica, Arial, 'DejaVu Sans', 'Liberation Sans', Freesans, sans-serif;
      margin: 5px 0;
      padding: 0;
      cursor: pointer;
    }
    .menu-group-desc {
      font-weight: 700;
      margin: 10px;
    }
    .menu-group-selected {
      background-color: darkslateblue !important;
      color: white;
    }
    &#13;
    <link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"/>
      <script src="//code.jquery.com/jquery-1.9.1.min.js"></script>
      <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
      <script src="//cdn.kendostatic.com/2014.2.903/js/kendo.all.min.js"></script>
      <h2>Group/Item Definitions</h2>
    
      <div id="menu-canvas">
        <div id="menu-group-panel" class="def-panel">
          <h3>Menu Groups</h3>
          <div id="menu-list" data-bind="foreach: menugroups">
            <div class="menu-group" data-bind="click: function() { mg.selectGroup($data) }, css: {'menu-group-selected': $parent.selectedGroup().MenuGroupId === $data.MenuGroupId}">
              <span class=" menu-group-handle">
    						&nbsp;
    					</span>
              <!--<span data-bind="click: function() { mg.selectGroup($data) }, css: {'menu-group-selected': $parent.selectedGroup().MenuGroupId === $data.MenuGroupId}" class="menu-group">
    					-->
              <span class="menu-group">
    						<button class="close menu-group-delete" data-bind="click: function() { mg.deleteGroup($data) } ">&times;</button>
    						<span class="menu-group-desc" data-bind="text: $data.Description"></span>
              <span data-bind="text: $data.DisplayOrder"></span>
              </span>
            </div>
          </div>
    
          <div class="menu-list">
            <button data-toggle="modal" data-target="#new-menu-group">New menu group...</button>
          </div>
    
          <div style="width: 800px;" data-bind="foreach: menugroups">
            <span data-bind="text: $data.DisplayOrder"></span>-<span data-bind="text: $data.Description"></span>,
          </div>
          <div class="modal fade" data-bind="with: newMenuGroup" id="new-menu-group">
            <div class="modal-dialog">
              <div class="modal-content">
                <div class="modal-header">
                  <button class="close" data-dismiss="modal">&times;</button>
                  <h3>New Menu Group</h3>
                </div>
                <div class="modal-body">
                  <form class="form-horizontal" id="add-menugroup" data-bind="submit: $parent.save">
                    <fieldset>
                      <div class="form-group">
                        <label class="control-label col-sm-2">Group Name</label>
                        <div class="col-sm-10">
                          <input class="form-control" data-bind="value: Description" type="text" id="menu-group-name" />
                        </div>
                      </div>
    
                      <div class="form-group">
                        <div class="col-sm-10 col-sm-push-2">
                          <div class="checkbox">
                            <input data-bind="checked: MenuActive" type="checkbox" />
                            <label>Menu group is active</label>
                          </div>
                        </div>
                      </div>
                    </fieldset>
                  </form>
                </div>
                <div class="modal-footer">
                  <a href="#" class="btn btn-primary" data-bind="click: $parent.save" data-dismiss="modal">Save Changes</a>
                  <a href="#" class="btn" data-dismiss="modal">Close</a>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    
      <script src="//ajax.aspnetcdn.com/ajax/knockout/knockout-3.1.0.debug.js"></script>
      <script src="//cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.3.0/bootbox.min.js"></script>
      <script src="//ajax.aspnetcdn.com/ajax/jquery.ui/1.10.4/jquery-ui.js"></script>
      <script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
    &#13;
    &#13;
    &#13;

1 个答案:

答案 0 :(得分:0)

将以下代码添加到MenuGroupsViewModel:

self.refresh = function () {
        var tempArray = self.menugroups().slice(0);
        self.menugroups([]);
        self.menugroups(tempArray);
    };

然后在self.deleteGroup函数中添加函数末尾的以下行:

self.refresh();

这会强制observableArray刷新。