Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
552 views
in Technique[技术] by (71.8m points)

javascript - Knockout is slow when unchecking checkboxes on a large (1000) dataset

I am using this code, to check all checkboxes on my view.

var checked = self.includeAllInSoundscript();
var contents = self.filterContents(self.getFilters());
for (var i = 0; i < contents.length; i++) {
   contents[i].includeInSoundscript(checked);
}
return true;

The checkbox

<input type="checkbox" data-bind="checked: includeInSoundscript" title="sometitle" />

This is what contents is:

(function (ko) {
ContentViewModel = function (data) {
    this.orderId = data.orderId;
    this.contentReferenceId = ko.observable(data.contentReferenceId);
    this.includeInSoundscript = ko.observable();
});

This is the filter methods:

self.getFilters = function() {
  var filterOrders = $.grep(self.orders(), function (order) {
    return (order.usedInfilter());
  });
  var filterLocations = $.grep(self.locations(), function (location)      {
    return (location.usedInfilter());
  });
  return { orders: filterOrders, locations: filterLocations };
};
self.filterContents = function (filter) {
  var filteredArray = self.contents();
  if (filter.orders.length > 0) {
      filteredArray = $.grep(filteredArray, function (content) {
        return $.grep(filter.orders, function (order) {
          return (order.orderId == content.orderId);
        }).length > 0;
      });
  }
  if (filter.locations.length > 0) {
      filteredArray = $.grep(filteredArray, function (content) {
                         return $.grep(filter.locations, function (location) {
                           return $.inArray(location.location, content.orderedFrom().split('/')) != -1;
  }).length > 0;
});
}
 return filteredArray;
};

Checking all checkboxes is fast, but when i uncheck, it can take up to 20 seconds. Strange thing is when the filetered result is small, it still takes a bit longer, even if the filtered results is about 40, from a total set of 1000.

The checkbox is in a table, bound using data-bind="foreach: contents"

I have now removed some of the "unescessary" observables, for properties that most likely will not change, it then behaves slightly better, but still very slow, especially in firefox. The big question is, why is this behavior only on unchecking checkboxes, and not on filtering, sorting, checking, etc.

Notice: Its only unchecking the checkboxes, basically when "checked" is false, otherwise its fast.

Edit: I am only displaying 50 items at a time, but i am checking / unchecking all the filtered items. This, so that I have controll over what to post to the server.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is what I use for this scenario. Maybe it will help you.

The checked binding can work with an array of selected items, but only supports storing strings in the array. I use a custom binding that supports storing objects in the array (like selectedOptions does):

ko.bindingHandlers.checkedInArray = {
    init: function (element, valueAccessor) {
        ko.utils.registerEventHandler(element, "click", function() {
            var options = ko.utils.unwrapObservable(valueAccessor()),
                array = options.array, // don't unwrap array because we want to update the observable array itself
                value = ko.utils.unwrapObservable(options.value),
                checked = element.checked;
            ko.utils.addOrRemoveItem(array, value, checked);
        });
    },
    update: function (element, valueAccessor) {
        var options = ko.utils.unwrapObservable(valueAccessor()),
            array = ko.utils.unwrapObservable(options.array),
            value = ko.utils.unwrapObservable(options.value);

        element.checked = ko.utils.arrayIndexOf(array, value) >= 0;
    }
};

The binding for each checkbox then looks like this:

<input type="checkbox" data-bind="checkedInArray: { array: $parent.selectedItems, value: $data }" />

The checkbox for selecting all items uses the normal checked binding and is attached to a writable computed observable:

this.allItemsSelected = ko.computed({
    read: function() {
        return this.selectedItems().length === this.items().length;
    },
    write: function(value) {
        this.selectedItems(value ? this.items.slice(0) : [] );
    },
    owner: this
});

Example: http://jsfiddle.net/mbest/L3LeD/

Update: Knockout 3.0.0 introduced the checkedValue binding option that makes the above custom binding unnecessary. You can now bind the checkboxes like this:

<input type="checkbox" data-bind="checked: $parent.selectedItems, checkedValue: $data" />

Example: http://jsfiddle.net/mbest/RLLX6/


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...