Jelajahi Sumber

Radio/Checkbox: fix radio-radiogroup checkbox-checkboxgroup nested bug fixed #1152

qingwei.li 8 tahun lalu
induk
melakukan
96f71eda55

+ 5 - 0
packages/checkbox/src/checkbox-group.vue

@@ -16,7 +16,12 @@
       value(value) {
         this.$emit('change', value);
         this.dispatch('form-item', 'el.form.change', [value]);
+        this.broadcast('ElCheckbox', 'initData', [value]);
       }
+    },
+
+    mounted() {
+      this.broadcast('ElCheckbox', 'initData', [this.value]);
     }
   };
 </script>

+ 45 - 49
packages/checkbox/src/checkbox.vue

@@ -17,11 +17,9 @@
         :disabled="disabled"
         :true-value="trueLabel"
         :false-value="falseLabel"
-        v-model="_value"
+        v-model="model"
         @focus="focus = true"
-        @blur="focus = false"
-        @change="handleChange"
-        ref="checkbox">
+        @blur="focus = false">
       <input
         v-else
         class="el-checkbox__original"
@@ -29,10 +27,9 @@
         :disabled="disabled"
         :value="label"
         :name="name"
-        v-model="_value"
+        v-model="model"
         @focus="focus = true"
-        @blur="focus = false"
-        @change="handleChange">
+        @blur="focus = false">
     </span>
     <span class="el-checkbox__label" v-if="$slots.default || label">
       <slot></slot>
@@ -48,70 +45,69 @@
 
     mixins: [Emitter],
 
-    props: {
-      value: {},
-      label: String,
-      indeterminate: Boolean,
-      disabled: Boolean,
-      checked: Boolean,
-      name: String,
-      trueLabel: [String, Number],
-      falseLabel: [String, Number]
-    },
+    componentName: 'ElCheckbox',
 
     computed: {
-      _value: {
+      model: {
         get() {
-          return !this.wrapInGroup ? this.value : this.$parent.value;
+          return this.isGroup ? this.store : this.value;
         },
-        set(newValue) {
-          if (!this.wrapInGroup) {
-            this.$emit('input', newValue);
+
+        set(val) {
+          if (this.isGroup) {
+            this.dispatch('ElCheckboxGroup', 'input', [val]);
           } else {
-            this.$parent.$emit('input', newValue);
+            this.$emit('input', val);
           }
         }
       },
-      isChecked() {
-        var type = Object.prototype.toString.call(this._value);
 
-        if (type === '[object Boolean]') {
-          return this._value;
-        } else if (type === '[object Array]') {
-          return this._value.indexOf(this.label) > -1;
-        } else if (type === '[object String]' || type === '[object Number]') {
-          return this._value === this.trueLabel;
+      isChecked() {
+        if ({}.toString.call(this.model) === '[object Boolean]') {
+          return this.model;
+        } else if (Array.isArray(this.model)) {
+          return this.model.indexOf(this.label) > -1;
+        } else if (this.model !== null && this.model !== undefined) {
+          return this.model === this.trueLabel;
         }
       }
     },
 
+    props: {
+      value: {},
+      label: String,
+      indeterminate: Boolean,
+      disabled: Boolean,
+      checked: Boolean,
+      name: String,
+      trueLabel: [String, Number],
+      falseLabel: [String, Number]
+    },
+
     data() {
       return {
-        focus: false,
-        wrapInGroup: this.$parent.$options.componentName === 'ElCheckboxGroup'
+        store: [],
+        isGroup: false
       };
     },
 
-    watch: {
-      checked: {
-        immediate: true,
-        handler(value) {
-          if (value) {
-            let type = Object.prototype.toString.call(this._value);
-            if (type !== '[object Array]') {
-              this._value = this.trueLabel || true;
-            } else {
-              this._value.push(this.label);
-            }
-          }
+    methods: {
+      addToStore() {
+        if (Array.isArray(this.model)) {
+          this.model.indexOf(this.label) === -1 && this.model.push(this.label);
+        } else {
+          this.model = this.trueLabel || true;
         }
       }
     },
 
-    methods: {
-      handleChange(ev) {
-        this.$emit('change', ev);
-      }
+    created() {
+      this.checked && this.addToStore();
+      this.$on('initData', data => {
+        this.store = data;
+        this.isGroup = true;
+        this.checked && this.addToStore();
+      });
     }
   };
 </script>

+ 5 - 1
packages/radio/src/radio-group.vue

@@ -4,7 +4,7 @@
   export default {
     name: 'ElRadioGroup',
 
-    componentName: 'radio-group',
+    componentName: 'ElRadioGroup',
 
     mixins: [Emitter],
 
@@ -15,8 +15,12 @@
     watch: {
       value(value) {
         this.$emit('change', value);
+        this.broadcast('ElRadio', 'initData', value);
         this.dispatch('form-item', 'el.form.change', [this.value]);
       }
+    },
+    mounted() {
+      this.broadcast('ElRadio', 'initData', this.value);
     }
   };
 </script>

+ 30 - 14
packages/radio/src/radio.vue

@@ -4,14 +4,14 @@
       <span class="el-radio__inner"
         :class="{
         'is-disabled': disabled,
-        'is-checked': _value === label,
+        'is-checked': store === label,
         'is-focus': focus
       }"></span>
       <input
         class="el-radio__original"
         :value="label"
         type="radio"
-        v-model="_value"
+        v-model="store"
         @focus="focus = true"
         @blur="focus = false"
         :name="name"
@@ -24,9 +24,15 @@
   </label>
 </template>
 <script>
+  import Emitter from 'element-ui/src/mixins/emitter';
+
   export default {
     name: 'ElRadio',
 
+    mixins: [Emitter],
+
+    componentName: 'ElRadio',
+
     props: {
       value: [String, Number],
       label: {
@@ -36,24 +42,34 @@
       disabled: Boolean,
       name: String
     },
+
     data() {
       return {
-        focus: false
+        focus: false,
+        isGroup: false,
+        store: this.value
       };
     },
-    computed: {
-      _value: {
-        get() {
-          return this.value !== undefined ? this.value : this.$parent.value;
-        },
-        set(newValue) {
-          if (this.value !== undefined) {
-            this.$emit('input', newValue);
-          } else {
-            this.$parent.$emit('input', newValue);
-          }
+
+    watch: {
+      store(store) {
+        if (this.isGroup) {
+          this.dispatch('ElRadioGroup', 'input', store);
+        } else {
+          this.$emit('input', store);
         }
+      },
+
+      value(val) {
+        this.store = val;
       }
+    },
+
+    created() {
+      this.$on('initData', data => {
+        this.store = data;
+        this.isGroup = true;
+      });
     }
   };
 </script>

+ 1 - 1
src/mixins/emitter.js

@@ -5,7 +5,7 @@ function broadcast(componentName, eventName, params) {
     if (name === componentName) {
       child.$emit.apply(child, [eventName].concat(params));
     } else {
-      broadcast.apply(child, [componentName, eventName].concat(params));
+      broadcast.apply(child, [componentName, eventName].concat([params]));
     }
   });
 }

+ 27 - 0
test/unit/specs/checkbox.spec.js

@@ -67,6 +67,33 @@ describe('Checkbox', () => {
       done();
     });
   });
+
+  it('nested group', done => {
+    vm = createVue({
+      template: `
+        <el-checkbox-group v-model="checkList">
+          <el-row>
+            <el-checkbox label="a" ref="a"></el-checkbox>
+            <el-checkbox label="b" ref="b"></el-checkbox>
+            <el-checkbox label="c" ref="c"></el-checkbox>
+            <el-checkbox label="d" ref="d"></el-checkbox>
+          </el-row>
+        </el-checkbox-group>
+      `,
+      data() {
+        return {
+          checkList: []
+        };
+      }
+    }, true);
+    expect(vm.checkList.length === 0).to.be.true;
+    vm.$refs.a.$el.click();
+    vm.$nextTick(_ => {
+      expect(vm.checkList.indexOf('a') !== -1).to.be.true;
+      done();
+    });
+  });
+
   it('true false label', done => {
     vm = createVue({
       template: `

+ 10 - 8
test/unit/specs/radio.spec.js

@@ -65,14 +65,16 @@ describe('Radio', () => {
         };
       }
     }, true);
-    expect(vm.$refs.radio1.$el.querySelector('.is-checked')).to.be.ok;
-    let radioElm = vm.$refs.radio2.$el;
-    radioElm.click();
-    vm.$nextTick(_ => {
-      expect(radioElm.querySelector('.is-checked')).to.be.ok;
-      expect(vm.radio === 6).to.be.true;
-      done();
-    });
+    setTimeout(_ => {
+      expect(vm.$refs.radio1.$el.querySelector('.is-checked')).to.be.ok;
+      let radioElm = vm.$refs.radio2.$el;
+      radioElm.click();
+      vm.$nextTick(_ => {
+        expect(radioElm.querySelector('.is-checked')).to.be.ok;
+        expect(vm.radio === 6).to.be.true;
+        done();
+      });
+    }, 50);
   });
   it('radio button', done => {
     vm = createVue({