简体   繁体   English

在ko.observableArray模型绑定问题中将项目下移

[英]Moving item down in ko.observableArray model binding issue

Edit 编辑

Apparently the logic is correct. 显然,逻辑是正确的。 I suspect the issue is with how I'm binding my View Model from the JSON response of our API. 我怀疑问题出在我如何从API的JSON响应中绑定视图模型。 I've added more code to try and help diagnose the issue. 我添加了更多代码以尝试帮助诊断问题。

Am I binding the view model correctly? 我是否正确绑定了视图模型?

Original post 原始帖子

I'm not asking how to move items around in an observableArray, I got my code to move items up and down inside an array from here: How do I swap two items in an observableArray? 我不是在问如何在observableArray中移动项目,我得到了从此处在数组内上下移动项目的代码: 如何在observableArray中交换两个项目?

Moving up by @Michael Best: https://stackoverflow.com/a/10630319/1888402 由@Michael Best上移: https ://stackoverflow.com/a/10630319/1888402

Moving down by @Moes: https://stackoverflow.com/a/26726556/1888402 由@Moes向下移动: https ://stackoverflow.com/a/26726556/1888402

The problem I'm having is moving the item down. 我遇到的问题是将物品下移。 It moves up just fine, the issue seems to be with the logic. 它上升得很好,问题似乎出在逻辑上。

JSON Model JSON模型

{
  "Options": {
    "SelectedHeader": "Left Header",
    "AvailableHeader": "Right Header"
  },
  "Selected": [
    {
      "Order": 2,
      "ID": 1,
      "Label": "Duration"
    },
    {
      "Order": 11,
      "ID": 5,
      "Label": "Metres / Min"
    },
    {
      "Order": 23,
      "ID": 7,
      "Label": "Sprint Dis/Min"
    },
    {
      "Order": 9,
      "ID": 15,
      "Label": "Max Velocity"
    },
    {
      "Order": 6,
      "ID": 16,
      "Label": "Hi Intensity Running"
    }
  ],
  "Available": [
    {
      "ID": 123,
      "Label": "I'm Available"
    }
  ],
  "WebServiceMethodUrl": "../../../Services/SomeAsmxService.asmx/SaveStuff"
}

View Model 查看模型

         function ViewModel(){
            var self = this;
            self.Options = model.Options
            self.Available = ko.observableArray(model.Available);
            self.Selected = ko.observableArray(model.Selected);
            self.WebServiceMethodUrl = model.WebServiceMethodUrl;
            self.addSelected = function(item){
                item.Order = self.Selected().length;
                self.Available.remove(item);
                self.Selected.push(item);
            };
            self.removeSelected = function(item){
                self.Available.push(item);
                self.Selected.remove(item);
            };
            self.moveUp = function(item) {
                var i = self.Selected.indexOf(item);
                if (i >= 1) {
                    var array = self.Selected();
                    self.Selected().splice(i-1, 2, array[i], array[i-1]); //Works fine
                    item.Order = i;
                }
            };
            self.moveDown = function(item) {
                var i = self.Selected.indexOf(item);
                if (i < self.Selected().length - 1) {
                    var array = self.Selected();
                    self.Selected().splice(i, 2, array[i + 1], array[i]);
                    item.Order = i;
                    self.Selected.valueHasMutated(); //Force rebind
                }
            };
            self.SaveIt = function(){
                postDataAsync(self.WebServiceMethodUrl, "{queryString: '"+ ko.toJSON(self) + "'}", "Could not save settings.", function (resp){});
            }
            self.sortedSelected = ko.computed(function(){
                return self.Selected().sort(function(left, right) { return left.Order == right.Order ? 0 : (left.Order < right.Order ? -1 : 1) });
            });
        }



        var vm = new ViewModel();

        ko.applyBindings(ViewModel);

HTML & Bindings HTML和绑定

 <!-- ko if: sortedSelected().length -->
   <tbody data-bind="with:sortedSelected">
        <!-- ko foreach: Selected -->
            <!-- ko ifnot: (ID == 0) -->
                <tr>
                    <td class="order">

                        <p data-bind="click: moveUp, clickBubble: false"><i class="fa fa-arrow-up"></i></p>
                        <p data-bind="text: $index() + 1"></p>
                        <p data-bind="click: moveDown, clickBubble: false"><i class="fa fa-arrow-down move-down"></i></p>
                    </td>
                    <td data-bind="text:Label, attr: { id: ID }"></td>
                    <td><a class="remove" data-bind="click: removeSelected, clickBubble: false">Remove&nbsp;&nbsp;<i class="fa fa-arrow-circle-o-right"></i></a></td>
                </tr>
            <!-- /ko-->
        <!-- /ko-->
    </tbody>
    <!-- /ko -->

So if I was to call the moveDown function on item 5, it should then become item 6 and item 6 should become item 5. Not sure why this isn't working since it's just the logic being inverted. 因此,如果我要在第5项上调用moveDown函数,则它应该变成第6项,而第6项应该变成第5项。不确定这为什么不起作用,因为这只是倒置的逻辑。

Example

JSFiddle JSFiddle

The problem is with your sortedSeleted computed. 问题出在您的sortedSeleted计算中。 Any time Selected is modified, the computed will be reevaluated because it has a dependency on Selected . 每当修改Selected ,都会重新评估计算值,因为它依赖于Selected When the computed is evaluated it sorts Selected . 对计算所得的值进行评估时,将对Selected进行排序。 You may have not realized that sort modifies the array it is called on while also returning the array. 您可能没有意识到sort会修改它调用的数组,同时还返回该数组。 This sorting by Order is what's making the moveUp and moveDown functions appear inconsistent. 这种按Order排序的原因是使moveUpmoveDown函数看起来不一致。

You most likely want to sort a copy of Selected . 您最有可能想要对Selected副本进行排序。 As @RoyJ pointed out, you can use slice to get a shallow copy of an array. 正如@RoyJ指出的那样,您可以使用slice来获取数组的浅表副本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM