Browse Source

Select: fix change event

Only emit change for user input

Before:
  select.value = 1;   // triggers change

After:
  select.value = 1;   // does not trigger change
wacky6.AriesMBP 8 years ago
parent
commit
fc242b6179
2 changed files with 56 additions and 1 deletions
  1. 23 1
      packages/select/src/select.vue
  2. 33 0
      test/unit/specs/select.spec.js

+ 23 - 1
packages/select/src/select.vue

@@ -114,6 +114,18 @@
     'mini': 22
   };
 
+  const valueEquals = (a, b) => {
+    // see: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
+    if (a === b) return true;
+    if (!(a instanceof Array)) return false;
+    if (!(b instanceof Array)) return false;
+    if (a.length !== b.length) return false;
+    for (let i = 0; i !== a.length; ++i) {
+      if (a[i] !== b[i]) return false;
+    }
+    return true;
+  };
+
   export default {
     mixins: [Emitter, Locale, Focus('reference')],
 
@@ -245,7 +257,6 @@
         if (this.filterable && !this.multiple) {
           this.inputLength = 20;
         }
-        this.$emit('change', val);
         this.dispatch('ElFormItem', 'el.form.change', val);
       },
 
@@ -365,6 +376,12 @@
         this.$nextTick(() => this.scrollToOption());
       },
 
+      emitChange(val) {
+        if (!valueEquals(this.value, val)) {
+          this.$emit('change', val);
+        }
+      },
+
       getOption(value) {
         let option;
         const type = typeof value;
@@ -471,6 +488,7 @@
           const value = this.value.slice();
           value.pop();
           this.$emit('input', value);
+          this.emitChange(value);
         }
       },
 
@@ -522,6 +540,7 @@
             value.push(option.value);
           }
           this.$emit('input', value);
+          this.emitChange(value);
           if (option.created) {
             this.query = '';
             this.inputLength = 20;
@@ -529,6 +548,7 @@
           if (this.filterable) this.$refs.input.focus();
         } else {
           this.$emit('input', option.value);
+          this.emitChange(option.value);
           this.visible = false;
         }
         this.$nextTick(() => this.scrollToOption());
@@ -605,6 +625,7 @@
       deleteSelected(event) {
         event.stopPropagation();
         this.$emit('input', '');
+        this.emitChange('');
         this.visible = false;
         this.$emit('clear');
       },
@@ -615,6 +636,7 @@
           const value = this.value.slice();
           value.splice(index, 1);
           this.$emit('input', value);
+          this.emitChange(value);
           this.$emit('remove-tag', tag);
         }
         event.stopPropagation();

+ 33 - 0
test/unit/specs/select.spec.js

@@ -692,4 +692,37 @@ describe('Select', () => {
       done();
     });
   });
+
+  it('only emit change on user input', done => {
+    let callCount = 0;
+    vm = createVue({
+      template: `
+        <div>
+          <el-select v-model="value" @change="change" ref="select">
+            <el-option label="1" :value="1" />
+            <el-option label="2" :value="2" />
+            <el-option label="3" :value="3" />
+          </el-select>
+        </div>
+      `,
+      data() {
+        return {
+          value: 1,
+          change: () => ++callCount
+        };
+      }
+    });
+
+    vm.value = 2;
+    setTimeout(() => {
+      expect(callCount).to.equal(0);
+      const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
+      triggerEvent(options[2], 'mouseenter');
+      options[2].click();
+      setTimeout(() => {
+        expect(callCount).to.equal(1);
+        done();
+      }, 10);
+    }, 10);
+  });
 });