【问题标题】:Moving item down in ko.observableArray model binding issue在 ko.observableArray 模型绑定问题中下移项目
【发布时间】:2015-10-09 02:23:07
【问题描述】:

编辑

显然逻辑是正确的。我怀疑问题在于我如何从我们 API 的 JSON 响应中绑定我的视图模型。我添加了更多代码来尝试帮助诊断问题。

我是否正确绑定了视图模型?

原帖

我不是在问如何在 observableArray 中移动项目,我的代码是从这里在数组中上下移动项目: How do I swap two items in an observableArray?

@Michael Best 向上移动:https://stackoverflow.com/a/10630319/1888402

@Moes 下移:https://stackoverflow.com/a/26726556/1888402

我遇到的问题是将项目向下移动。它移动得很好,问题似乎与逻辑有关。

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"
}

查看模型

         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 和绑定

 <!-- 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 -->

因此,如果我要在第 5 项上调用 moveDown 函数,那么它应该成为第 6 项,第 6 项应该成为第 5 项。不知道为什么这不起作用,因为它只是逻辑被反转了。

示例

JSFiddle

【问题讨论】:

  • 它对我有用。此外,如果您在可观察数组而不是后备数组上调用 splice,则无需调用 valueHasMutated。此外,如果在数组中的最后一个索引上使用,这将无法正常工作。将您的支票更改为i &lt; self.Selected().length - 1
  • 有趣,我将不得不发布更多我的代码。
  • 您没有使用 Knockout 的 splice。在 observableArray 上调用它,而不是在内容上。
  • 请做一个小提琴来告诉我们什么是行不通的。
  • 一旦你解决了这个问题,你会注意到你的绑定的所有上下文问题。例如,您不能在 with: sortedSelected 中包含 foreach: Selected,因为 sortedSelected 没有名为“Selected”的属性。

标签: javascript arrays knockout.js


【解决方案1】:

问题在于您的 sortedSeleted 计算得到。任何时候修改Selected,都会重新计算计算值,因为它依赖于Selected。当计算的被评估时,它排序Selected。你可能没有意识到sort 修改了它被调用的数组,同时也返回了数组。 Order 的这种排序是导致moveUpmoveDown 函数出现不一致的原因。

您很可能想要对Selected副本进行排序。正如@RoyJ 指出的那样,您可以使用slice 来获取数组的浅拷贝。

【讨论】:

  • 并且要排序而不重新排列,您可以对整个数组进行切片:self.Selected.slice().sort(...
  • 非常感谢@CrimsonChris,有很多问题,但你帮我解决了问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-16
  • 2014-06-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多