Jelajahi Sumber

only sync $value change inside v-repeat back to original array for primitive values (fix #853)

Evan You 11 tahun lalu
induk
melakukan
59cf0cc36d

+ 20 - 12
src/directive.js

@@ -203,23 +203,31 @@ p._teardown = function () {
  * e.g. v-model.
  *
  * @param {*} value
- * @param {Boolean} lock - prevent wrtie triggering update.
  * @public
  */
 
-p.set = function (value, lock) {
+p.set = function (value) {
   if (this.twoWay) {
-    if (lock) {
-      this._locked = true
-    }
-    this._watcher.set(value)
-    if (lock) {
-      var self = this
-      _.nextTick(function () {
-        self._locked = false
-      })
-    }
+    this._withLock(function () {
+      this._watcher.set(value)
+    })
   }
 }
 
+/**
+ * Execute a function while preventing that function from
+ * triggering updates on this directive instance.
+ *
+ * @param {Function} fn
+ */
+
+p._withLock = function (fn) {
+  var self = this
+  self._locked = true
+  fn.call(self)
+  _.nextTick(function () {
+    self._locked = false
+  })
+}
+
 module.exports = Directive

+ 1 - 1
src/directives/model/checkbox.js

@@ -6,7 +6,7 @@ module.exports = {
     var self = this
     var el = this.el
     this.listener = function () {
-      self.set(el.checked, true)
+      self.set(el.checked)
     }
     _.on(el, 'change', this.listener)
     if (el.checked) {

+ 4 - 4
src/directives/model/default.js

@@ -32,10 +32,10 @@ module.exports = {
 
     // shared setter
     function set () {
-      self.set(
-        number ? _.toNumber(el.value) : el.value,
-        true
-      )
+      var val = number
+        ? _.toNumber(el.value)
+        : el.value
+      self.set(val)
     }
 
     // if the directive has filters, we need to

+ 1 - 1
src/directives/model/radio.js

@@ -6,7 +6,7 @@ module.exports = {
     var self = this
     var el = this.el
     this.listener = function () {
-      self.set(el.value, true)
+      self.set(el.value)
     }
     _.on(el, 'change', this.listener)
     if (el.checked) {

+ 1 - 1
src/directives/model/select.js

@@ -23,7 +23,7 @@ module.exports = {
           ? value.map(_.toNumber)
           : _.toNumber(value)
         : value
-      self.set(value, true)
+      self.set(value)
     }
     _.on(el, 'change', this.listener)
     checkInitialValue.call(this)

+ 18 - 11
src/directives/repeat.js

@@ -288,7 +288,10 @@ module.exports = {
         }
       } else { // new instance
         vm = this.build(obj, i, true)
-        vm._new = true
+        // the _new flag is used in the second pass for
+        // vm cache retrival, but if this is the init phase
+        // the flag can just be set to false directly.
+        vm._new = !init
         vm._reused = false
       }
       vms[i] = vm
@@ -395,16 +398,20 @@ module.exports = {
     if (needCache) {
       this.cacheVm(raw, vm, this.converted ? meta.$key : null)
     }
-    // sync back changes for $value, particularly for
-    // two-way bindings of primitive values
-    var self = this
-    vm.$watch('$value', function (val) {
-      if (self.converted) {
-        self.rawValue[vm.$key] = val
-      } else {
-        self.rawValue.$set(vm.$index, val)
-      }
-    })
+    // sync back changes for two-way bindings of primitive values
+    var type = typeof raw
+    if (type === 'string' || type === 'number') {
+      var dir = this
+      vm.$watch(alias || '$value', function (val) {
+        dir._withLock(function () {
+          if (dir.converted) {
+            dir.rawValue[vm.$key] = val
+          } else {
+            dir.rawValue.$set(vm.$index, val)
+          }
+        })
+      })
+    }
     return vm
   },
 

+ 8 - 1
src/filters/array-filters.js

@@ -79,12 +79,19 @@ exports.orderBy = function (arr, sortKey, reverseKey) {
  */
 
 function contains (val, search) {
-  if (_.isObject(val)) {
+  if (_.isPlainObject(val)) {
     for (var key in val) {
       if (contains(val[key], search)) {
         return true
       }
     }
+  } else if (_.isArray(val)) {
+    var i = val.length
+    while (i--) {
+      if (contains(val[i], search)) {
+        return true
+      }
+    }
   } else if (val != null) {
     return val.toString().toLowerCase().indexOf(search) > -1
   }

+ 3 - 10
test/unit/specs/directive_spec.js

@@ -136,16 +136,9 @@ describe('Directive', function () {
     d.set(2)
     expect(vm.a).toBe(6)
     nextTick(function () {
-      expect(def.update.calls.count()).toBe(2)
-      expect(def.update).toHaveBeenCalledWith(6, 1)
-      // locked set
-      d.set(3, true)
-      expect(vm.a).toBe(9)
-      nextTick(function () {
-        // should have no update calls
-        expect(def.update.calls.count()).toBe(2)
-        done()
-      })
+      // should have no update calls
+      expect(def.update.calls.count()).toBe(1)
+      done()
     })
   })
 

+ 5 - 1
test/unit/specs/filters/filters_spec.js

@@ -100,7 +100,7 @@ describe('Filters', function () {
     var arr = [
       { a: 1, b: { c: 'hello' }},
       { a: 2, b: 'hello'},
-      { a: 3, b: 2 }
+      { a: 3, b: ['yoyo'] }
     ]
     var vm = new Vue({
       data: {
@@ -135,6 +135,10 @@ describe('Filters', function () {
     // number search key
     res = filter.call(vm, arr, 'search.n')
     expect(res[0]).toBe(arr[1])
+    // search in sub array
+    res = filter.call(vm, arr, "'yoyo'")
+    expect(res.length).toBe(1)
+    expect(res[0]).toBe(arr[2])
   })
 
   it('orderBy', function () {