浏览代码

Only trigger 'selection:update' once on DOM change events (#5734)

* Only trigger 'selection:update' once on DOM change events

* Fix linting errors

* Add test for adding multiple options to a select

* Switch Array.isArray to jQuery.isArray

Because we're still doing best-effort IE8 support for some reason.

* Fixed formatting in tests

Co-authored-by: Kevin Brown <[email protected]>
David Bramwell 5 年之前
父节点
当前提交
e0855a2f65
共有 2 个文件被更改,包括 62 次插入3 次删除
  1. 18 3
      src/js/select2/core.js
  2. 44 0
      tests/integration/dom-changes.js

+ 18 - 3
src/js/select2/core.js

@@ -208,8 +208,8 @@ define([
 
     if (observer != null) {
       this._observer = new observer(function (mutations) {
-        $.each(mutations, self._syncA);
-        $.each(mutations, self._syncS);
+        self._syncA();
+        self._syncS(null, mutations);
       });
       this._observer.observe(this.$element[0], {
         attributes: true,
@@ -376,7 +376,7 @@ define([
     }
   };
 
-  Select2.prototype._syncSubtree = function (evt, mutations) {
+  Select2.prototype._isChangeMutation = function (evt, mutations) {
     var changed = false;
     var self = this;
 
@@ -404,7 +404,22 @@ define([
       }
     } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
       changed = true;
+    } else if ($.isArray(mutations)) {
+      $.each(mutations, function(evt, mutation) {
+        if (self._isChangeMutation(evt, mutation)) {
+          // We've found a change mutation.
+          // Let's escape from the loop and continue
+          changed = true;
+          return false;
+        }
+      });
     }
+    return changed;
+  };
+
+  Select2.prototype._syncSubtree = function (evt, mutations) {
+    var changed = this._isChangeMutation(evt, mutations);
+    var self = this;
 
     // Only re-pull the data if we think there is a change
     if (changed) {

+ 44 - 0
tests/integration/dom-changes.js

@@ -1,3 +1,4 @@
+/*jshint browser: true */
 module('DOM integration');
 
 test('adding a new unselected option changes nothing', function (assert) {
@@ -286,3 +287,46 @@ test('searching tags does not loose focus', function (assert) {
   select.selection.trigger('query', {term: 'f'});
   select.selection.trigger('query', {term: 'ff'});
 });
+
+
+test('adding multiple options calls selection:update once', function (assert) {
+  assert.expect(1);
+
+  var asyncDone = assert.async();
+
+  var $ = require('jquery');
+  var Select2 = require('select2/core');
+
+  var content = '<select>';
+  var options = '';
+
+  for (var i = 0; i < 4000; i++) {
+    options += '<option>' + i + '</option>';
+  }
+
+  content += options;
+  content += '</select>';
+
+  var $select = $(content);
+
+  $('#qunit-fixture').append($select);
+
+  var select = new Select2($select);
+
+  var eventCalls = 0;
+
+  select.on('selection:update', function () {
+    eventCalls++;
+  });
+
+  $select.html(options);
+
+  setTimeout(function () {
+    assert.equal(
+      eventCalls,
+      1,
+      'selection:update was called more than once'
+    );
+    asyncDone();
+  }, 0);
+});