您好,感谢您一看。
我有一个非常深层次的动态调查:
<assessment>
<criterionTypes>
<criterionType>
<criteria>
<criterion>
<responses>
<response>
<assessmentResponses>
<assessmentResponse>
偶尔,我会让数组中的一些可观察项目以正确的顺序绑定到表单。
尽管我迭代了该集合,但在将其交给视图之前调整排序,甚至在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, 过渡:&#39;入口&#39;}
我不知道如何继续这样做。也许是一个可以对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> </div>
<!-- /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>
答案 0 :(得分:2)
如何处理排序数组取决于您的应用程序设计。最重要的问题通常是“排序对模型重要还是仅对视图(UI)?”
如果它对视图唯一重要,那么您无需担心视图模型中的数据是否已排序。您只需对视图中显示的内容进行排序即可。为此,您可以绑定到已排序的数组的副本:
foreach: criteria.slice(0).sort(criteriaSortingFunction)
您也可以在视图模型中使用计算的observable来帮助保持视图清洁:
this.sortedCriteria = ko.computed(function () {
return criteria.slice(0).sort(criteriaSortingFunction);
}, this);
如果在模型中对数据进行排序很重要,那么一种方法是确保在更新observable之前对数据进行排序:
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});
答案 1 :(得分:1)
除了迈克尔的回答之外,我想澄清对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中的自动依赖跟踪机制。
在控制台中尝试此操作
// 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);