Skip to content

Commit fba83d3

Browse files
eladFrizifoxbenjaminfox
authored andcommitted
added support for watch as array and moved all the watch logic to seprate module. (#66)
* added support for watch as array and moved all the watch logic to separate module * added unit testing to the watch options, as array and as function * added error when input of watch is not valid
1 parent 778f612 commit fba83d3

File tree

4 files changed

+194
-12
lines changed

4 files changed

+194
-12
lines changed

Diff for: package-lock.json

+21-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/index.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
silentGetLazy,
77
silentSetLazy,
88
} from './lazy'
9+
import { getWatchedGetter } from './watch'
10+
911

1012
const prefix = '_async_computed$'
1113
const DidNotUpdate = typeof Symbol === 'function' ? Symbol('did-not-update') : {}
@@ -137,11 +139,7 @@ function getterFn (key, fn) {
137139
let getter = fn.get
138140

139141
if (fn.hasOwnProperty('watch')) {
140-
const previousGetter = getter
141-
getter = function getter () {
142-
fn.watch.call(this)
143-
return previousGetter.call(this)
144-
}
142+
getter = getWatchedGetter(fn)
145143
}
146144

147145
if (fn.hasOwnProperty('shouldUpdate')) {

Diff for: src/watch.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const getGetterWatchedByArray = computedAsyncProperty =>
2+
function getter() {
3+
for (let key of computedAsyncProperty.watch) {
4+
if (typeof key !== 'string') throw new Error('AsyncComputed: watch elemnts must be strings')
5+
// check if nested key is watched
6+
const splittedByDot = key.split('.');
7+
if (splittedByDot.length === 1) {
8+
// if not just access it
9+
this[key]
10+
} else {
11+
// access nested propety
12+
try {
13+
var start = this
14+
for (let part of splittedByDot) {
15+
start = start[part]
16+
}
17+
} catch (error) {
18+
console.error('computedAsyncPlugin: bad path: ', key)
19+
throw error
20+
}
21+
}
22+
}
23+
return computedAsyncProperty.get.call(this)
24+
}
25+
26+
const getGetterWatchedByFunction = computedAsyncProperty =>
27+
function getter() {
28+
computedAsyncProperty.watch.call(this)
29+
return computedAsyncProperty.get.call(this)
30+
}
31+
32+
33+
export function getWatchedGetter(computedAsyncProperty) {
34+
if (typeof computedAsyncProperty.watch === 'function') {
35+
return getGetterWatchedByFunction(computedAsyncProperty)
36+
} else if (Array.isArray(computedAsyncProperty.watch)) {
37+
return getGetterWatchedByArray(computedAsyncProperty)
38+
} else {
39+
throw Error('AsyncComouted: watch should be function or an array')
40+
}
41+
}

Diff for: test/index.js

+129
Original file line numberDiff line numberDiff line change
@@ -885,3 +885,132 @@ test('Data of component still work as function and got vm', t => {
885885
})
886886
t.equal(vm, _vmContext)
887887
})
888+
889+
890+
test("Watch as a function", t => {
891+
t.plan(4)
892+
let i = 0
893+
const vm = new Vue({
894+
data: {
895+
y: 2,
896+
obj: {
897+
t: 0
898+
}
899+
},
900+
asyncComputed: {
901+
z: {
902+
get () {
903+
return Promise.resolve(i + this.y)
904+
},
905+
watch(){
906+
this.obj.t
907+
}
908+
}
909+
}
910+
})
911+
t.equal(vm.z, null)
912+
Vue.nextTick(() => {
913+
t.equal(vm.z, 2)
914+
i++
915+
vm.obj.t--
916+
Vue.nextTick(() => {
917+
// This tick, Vue registers the change
918+
// in the watcher, and reevaluates
919+
// the getter function
920+
t.equal(vm.z, 2)
921+
Vue.nextTick(() => {
922+
// Now in this tick the promise has
923+
// resolved, and z is 3.
924+
t.equal(vm.z, 3)
925+
})
926+
})
927+
})
928+
})
929+
930+
931+
test("Watchers as array with nested path rerun the computation when a value changes", t => {
932+
t.plan(4)
933+
let i = 0
934+
const vm = new Vue({
935+
data: {
936+
y: 2,
937+
obj: {
938+
t: 0
939+
}
940+
},
941+
asyncComputed: {
942+
z: {
943+
get () {
944+
return Promise.resolve(i + this.y)
945+
},
946+
watch: ['obj.t']
947+
}
948+
}
949+
})
950+
t.equal(vm.z, null)
951+
Vue.nextTick(() => {
952+
t.equal(vm.z, 2)
953+
i++
954+
vm.obj.t--
955+
Vue.nextTick(() => {
956+
// This tick, Vue registers the change
957+
// in the watcher, and reevaluates
958+
// the getter function
959+
t.equal(vm.z, 2)
960+
Vue.nextTick(() => {
961+
// Now in this tick the promise has
962+
// resolved, and z is 3.
963+
t.equal(vm.z, 3)
964+
})
965+
})
966+
})
967+
})
968+
969+
test("Watch as array with more then one value", t => {
970+
t.plan(5)
971+
let i = 0
972+
const vm = new Vue({
973+
data: {
974+
y: 2,
975+
obj: {
976+
t: 0
977+
},
978+
r:0
979+
},
980+
asyncComputed: {
981+
z: {
982+
get () {
983+
return Promise.resolve(i + this.y)
984+
},
985+
watch: ['obj.t', 'r']
986+
}
987+
}
988+
})
989+
t.equal(vm.z, null)
990+
Vue.nextTick(() => {
991+
t.equal(vm.z, 2)
992+
i++
993+
// checking for nested property
994+
vm.obj.t--
995+
Vue.nextTick(() => {
996+
// This tick, Vue registers the change
997+
// in the watcher, and reevaluates
998+
// the getter function
999+
t.equal(vm.z, 2)
1000+
Vue.nextTick(() => {
1001+
// Now in this tick the promise has
1002+
// resolved, and z is 3.
1003+
t.equal(vm.z, 3)
1004+
1005+
i++
1006+
// one level and multiple watchers
1007+
vm.r--
1008+
Vue.nextTick(()=>{
1009+
Vue.nextTick(() => {
1010+
t.equal(vm.z,4)
1011+
})
1012+
})
1013+
})
1014+
})
1015+
})
1016+
})

0 commit comments

Comments
 (0)