代码之家  ›  专栏  ›  技术社区  ›  James Fleming

当使用排序时,每个都不显示新项目

  •  0
  • James Fleming  · 技术社区  · 11 年前

    你好,谢谢你看一看。

    Screen shot 我有一个层次很深的动态调查:

    <assessment>
        <criterionTypes>
          <criterionType>
            <criteria>
              <criterion>
                <responses>
                  <response>
                    <assessmentResponses>
                      <assessmentResponse>
    

    有时,我会让数组中的一些可观察项没有以正确的顺序绑定到表单。

    enter image description here 尽管我对该集合进行了迭代,在将其移交给视图之前调整了排序,甚至在Chrome调试器中以正确的顺序看到了该列表,但还是出现了这种情况。我能够通过将排序例程应用于foreach来解决这个问题,该例程用于那些行为不好的集合。像这样:

      <!-- ko foreach: criterionTypes -->
      <div data-bind="foreach: criteria.sort($root.context.sort.criteria),
    

    <!-- ko foreach: assessmentResponses.sort(function (l, r) { return (l.id() == r.id()) ? (l.id() > r.id() ? -1 : 1) : (l.id() > r.id() ? -1 : 1) }) ... -->
    

    到现在为止,一直都还不错。然而,我有一个功能,用户可以在其中添加新行,当模型在淘汰赛中更新时,UI将不会反映这些更改。因此,如果我放弃排序,模型绑定就会工作,UI也会按预期更新。

    在我的更新按钮中,我尝试重新绑定我的点击事件:

    var addResponse = function (response) {
            core.addResponse(assessment(), response); 
            ko.applyBindings(assessment);
        };
    

    但无论我试图绑定什么对象(评估、响应等),我最终都会犯同样的错误

    未捕获错误:无法分析绑定。 消息:ReferenceError:未定义路由器; 绑定值:compose:{model:router.activeItem, afterCompose:router.afterCompose, 过渡:'入口'}

    我不知道我该怎么做。也许是一个自定义绑定,它可以对foreach执行排序,但我无法对其进行排序(双关语)。

        <div id="boolean.secondaryResponse" data-bind="if: isSecondaryResponse(), visible: $parent.showSecondaryResponse()>
    <!-- ko foreach: assessmentResponses.sort(function (l, r) { return (l.id() == r.id()) ? (l.id() > r.id() ? -1 : 1) : (l.id() > r.id() ? -1 : 1) }) -->                      
                              <!-- ko if: customResponse().template() == 'ingredientSource'-->
                              <div class="col-md-2 col-lg-2" style="z-index: 10"><select data-bind="value: explanation, options: $root.controls.ingredientOrigins, event: { change: $root.context.selectionChanged }, attr: { class: 'form-control ' + criterionCode() + ' ordinal-' + customResponse().ordinal() } " class="remove"></select> &nbsp;</div>&nbsp;
                              <!-- /ko -->
                              <!-- ko if: customResponse().template().startsWith('span')-->
                              <div data-bind="attr: { class: customResponse().template() + ' col-sm-2  col-md-4' }" style="margin-left: -10px; z-index: 10; height: 69px"><input type="text" data-bind="value: textualResponse, attr: { class: 'form-control auto' + customResponse().name() + ' ordinal-' + customResponse().ordinal(), placeholder: customResponse().placeholder }" class="remove" /></div>
                              <!--/ko -->
                              <!-- /ko -->
                              <!-- /ko -->
    </div>
    
    2 回复  |  直到 11 年前
        1
  •  2
  •   Michael Best    11 年前

    如何处理排序数组取决于应用程序设计。最重要的问题通常是“排序对模型重要还是仅对视图(UI)重要?”

    为视图排序

    如果它只对视图重要,那么您不必担心将视图模型中的数据排序。您只需要按视图中显示的方式对其进行排序。为此,您可以绑定到已排序数组的副本:

    foreach: criteria.slice(0).sort(criteriaSortingFunction)
    

    您也可以在视图模型中使用计算的可观察值来实现这一点,以帮助保持视图的整洁:

    this.sortedCriteria = ko.computed(function () {
        return criteria.slice(0).sort(criteriaSortingFunction);
    }, this);
    

    为模型排序

    如果在模型中对数据进行排序很重要,那么一种方法是确保在更新可观察数据之前对数据进行了排序:

    this.addCriteria(toAdd) {
        var rawArray = this.criteria();
        rawArray.push(toAdd);
        rawArray.sort(criteriaSortingFunction);
        this.criteria(rawArray);
    }
    

    如果在很多地方更新阵列,这可能会重复。或者,您可以添加一个扩展程序,使阵列保持排序:

    ko.extenders.sorted = function (obs, sortFunction) {
        obs.sort(sortFunction);
        obs.subscribe(function (array) {
            array.sort(sortFunction);
        });
    }
    

    这可以在视图模型构造函数中应用,如下所示:

    this.criteria = ko.observableArray(initialCriteria).extend({sorted: criteriaSortingFunction});
    
        2
  •  1
  •   huocp    11 年前

    除了迈克尔的回答,我还想澄清一下对ko的一些理解 observableArray.sort() .

    在控制台中试用

    > var arr = ko.observableArray([3,1,4,2]);
    > var b = arr.sort();
    > arr();  // arr.sort() mutate arr itself
    < [1, 2, 3, 4]
    > ko.isObservable(b); // result of arr.sort() is not a observable
    < false
    > b
    < [1, 2, 3, 4]
    

    在ko中,绑定中的任何非平凡表达式都会自动包装为 ko.computed ( ko.dependentObservable ). 对于 data-bind="foreach: arr.sort()" ,ko将创建一个 ko.computed(function() { return arr.sort();})

    这里的问题是 arr.sort() 不会触发ko中的自动依赖跟踪机制。

    在Console中尝试此操作

    // k1 is not dependent on arr!
    // (I'm not sure whether this is intended in knockout)
    > var k1 = ko.computed(function() { return arr.sort();});
    > k1.getDependenciesCount();
    < 0
    > arr.getSubscriptionsCount();
    < 0
    
    // k2 is dependent on arr!
    > var k2 = ko.computed(function() { return arr().sort();});
    > k2.getDependenciesCount();
    < 1
    > arr.getSubscriptionsCount();
    < 1
    

    下面是一个演示 k1 不响应arr更改,但 k2 http://jsfiddle.net/gfHz3/8/

    因此,一个简单的解决方案是 assessmentResponses().sort(...)

    本地人 sort(...) 在…上 assessmentResponses() 仍然会改变内容 assessmentResponses 持有。在Michael的回答中,他使用 slice(0) 为了解决依赖性问题,它还具有在排序之前复制数组的效果。就我个人而言,我总是使用 underscore sortBy 非破坏性功能。

    顺便说一下,还有一件事,这条线

    return (l.id() == r.id()) ? (l.id() > r.id() ? -1 : 1) : (l.id() > r.id() ? -1 : 1);
    

    与完全相同

    return l.id() > r.id() ? -1 : 1;
    

    我想你想写以下内容?

    return (l.id() == r.id()) ? 0 : (l.id() > r.id() ? -1 : 1);
    
    推荐文章