Skip to content

Commit 0e486a3

Browse files
committed
repeat object sync and tests
1 parent e749452 commit 0e486a3

File tree

3 files changed

+150
-7
lines changed

3 files changed

+150
-7
lines changed

src/directives/repeat.js

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,35 @@ var Observer = require('../observer'),
1212
var mutationHandlers = {
1313

1414
push: function (m) {
15-
var i, l = m.args.length,
15+
var l = m.args.length,
1616
base = this.collection.length - l
17-
for (i = 0; i < l; i++) {
17+
for (var i = 0; i < l; i++) {
1818
this.buildItem(m.args[i], base + i)
19+
this.updateObject(m.args[i], 1)
1920
}
2021
},
2122

2223
pop: function () {
2324
var vm = this.vms.pop()
24-
if (vm) vm.$destroy()
25+
if (vm) {
26+
vm.$destroy()
27+
this.updateObject(vm.$data, -1)
28+
}
2529
},
2630

2731
unshift: function (m) {
28-
m.args.forEach(this.buildItem, this)
32+
for (var i = 0, l = m.args.length; i < l; i++) {
33+
this.buildItem(m.args[i], i)
34+
this.updateObject(m.args[i], 1)
35+
}
2936
},
3037

3138
shift: function () {
3239
var vm = this.vms.shift()
33-
if (vm) vm.$destroy()
40+
if (vm) {
41+
vm.$destroy()
42+
this.updateObject(vm.$data, -1)
43+
}
3444
},
3545

3646
splice: function (m) {
@@ -41,9 +51,11 @@ var mutationHandlers = {
4151
removedVMs = this.vms.splice(index, removed)
4252
for (i = 0, l = removedVMs.length; i < l; i++) {
4353
removedVMs[i].$destroy()
54+
this.updateObject(removedVMs[i].$data, -1)
4455
}
4556
for (i = 0; i < added; i++) {
4657
this.buildItem(m.args[i + 2], index + i)
58+
this.updateObject(m.args[i + 2], 1)
4759
}
4860
},
4961

@@ -136,12 +148,14 @@ module.exports = {
136148
var method = mutation.method
137149
mutationHandlers[method].call(self, mutation)
138150
if (method !== 'push' && method !== 'pop') {
151+
// update index
139152
var i = arr.length
140153
while (i--) {
141154
arr[i].$index = i
142155
}
143156
}
144157
if (method === 'push' || method === 'unshift' || method === 'splice') {
158+
// recalculate dependency
145159
self.changed()
146160
}
147161
}
@@ -150,13 +164,19 @@ module.exports = {
150164

151165
update: function (collection, init) {
152166

167+
if (
168+
collection === this.collection ||
169+
collection === this.object
170+
) return
171+
153172
if (utils.typeOf(collection) === 'Object') {
173+
if (this.object) {
174+
delete this.object.$repeater
175+
}
154176
this.object = collection
155177
collection = objectToArray(collection)
156178
def(this.object, '$repeater', collection, false, true)
157179
}
158-
159-
if (collection === this.collection) return
160180

161181
this.reset()
162182
// attach an object to container to hold handlers
@@ -314,6 +334,26 @@ module.exports = {
314334
}
315335
},
316336

337+
/**
338+
* Sync changes in the $repeater Array
339+
* back to the represented Object
340+
*/
341+
updateObject: function (data, action) {
342+
if (this.object && data.$key) {
343+
var key = data.$key,
344+
val = data.$value || data
345+
if (action > 0) { // new property
346+
// make key ienumerable
347+
delete data.$key
348+
def(data, '$key', key, false, true)
349+
this.object[key] = val
350+
} else {
351+
delete this.object[key]
352+
}
353+
this.object.__observer__.emit('set', key, val, true)
354+
}
355+
},
356+
317357
reset: function (destroyAll) {
318358
if (this.childId) {
319359
delete this.vm.$[this.childId]
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<div id="test">
2+
<ul>
3+
<li class="primitive" v-repeat="primitive">{{$key}} {{$value}}</li>
4+
</ul>
5+
<ul>
6+
<li class="obj" v-repeat="obj">{{$key}} {{msg}}</li>
7+
</ul>
8+
<button id="push" v-on="click:t1">push to primitive</button>
9+
<button id="pop" v-on="click:t2">pop from primitive</button>
10+
<button id="shift" v-on="click:t3">shift from object</button>
11+
<button id="unshift" v-on="click:t4">unshift to object</button>
12+
<button id="splice" v-on="click:t5">splice in object</button>
13+
<p id="primitive">{{primitive}}</p>
14+
<p id="obj">{{obj}}</p>
15+
</div>
16+
17+
<script src="../../../dist/vue.js"></script>
18+
<script>
19+
var test = new Vue({
20+
el: '#test',
21+
data: {
22+
primitive: {
23+
a: 1,
24+
b: 2
25+
},
26+
obj: {
27+
a: { msg: 'hi!' },
28+
b: { msg: 'ha!' }
29+
}
30+
},
31+
methods: {
32+
t1: function () {
33+
this.primitive.$repeater.push({
34+
$key: 'c',
35+
$value: 3
36+
})
37+
},
38+
t2: function () {
39+
this.primitive.$repeater.pop()
40+
},
41+
t3: function () {
42+
this.obj.$repeater.shift()
43+
},
44+
t4: function () {
45+
this.obj.$repeater.unshift({
46+
$key: 'c',
47+
msg: 'ho!'
48+
})
49+
},
50+
t5: function () {
51+
this.obj.$repeater.splice(1, 1, {
52+
$key: 'd',
53+
msg: 'he!'
54+
})
55+
}
56+
}
57+
})
58+
</script>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
casper.test.begin('Repeat properties of an Object', 24, function (test) {
2+
3+
casper
4+
.start('./fixtures/repeat-object.html')
5+
.then(function () {
6+
test.assertElementCount('.primitive', 2)
7+
test.assertElementCount('.obj', 2)
8+
test.assertSelectorHasText('.primitive:nth-child(1)', 'a 1')
9+
test.assertSelectorHasText('.primitive:nth-child(2)', 'b 2')
10+
test.assertSelectorHasText('.obj:nth-child(1)', 'a hi!')
11+
test.assertSelectorHasText('.obj:nth-child(2)', 'b ha!')
12+
test.assertSelectorHasText('#primitive', '{"a":1,"b":2}')
13+
test.assertSelectorHasText('#obj', '{"a":{"msg":"hi!"},"b":{"msg":"ha!"}}')
14+
})
15+
.thenClick('#push', function () {
16+
test.assertElementCount('.primitive', 3)
17+
test.assertSelectorHasText('.primitive:nth-child(3)', 'c 3')
18+
test.assertSelectorHasText('#primitive', '{"a":1,"b":2,"c":3}')
19+
})
20+
.thenClick('#pop', function () {
21+
test.assertElementCount('.primitive', 2)
22+
test.assertSelectorHasText('#primitive', '{"a":1,"b":2}')
23+
})
24+
.thenClick('#shift', function () {
25+
test.assertElementCount('.obj', 1)
26+
test.assertSelectorHasText('.obj:nth-child(1)', 'b ha!')
27+
test.assertSelectorHasText('#obj', '{"b":{"msg":"ha!"}}')
28+
})
29+
.thenClick('#unshift', function () {
30+
test.assertElementCount('.obj', 2)
31+
test.assertSelectorHasText('.obj:nth-child(1)', 'c ho!')
32+
test.assertSelectorHasText('.obj:nth-child(2)', 'b ha!')
33+
test.assertSelectorHasText('#obj', '{"b":{"msg":"ha!"},"c":{"msg":"ho!"}}')
34+
})
35+
.thenClick('#splice', function () {
36+
test.assertElementCount('.obj', 2)
37+
test.assertSelectorHasText('.obj:nth-child(1)', 'c ho!')
38+
test.assertSelectorHasText('.obj:nth-child(2)', 'd he!')
39+
test.assertSelectorHasText('#obj', '{"c":{"msg":"ho!"},"d":{"msg":"he!"}}')
40+
})
41+
.run(function () {
42+
test.done()
43+
})
44+
45+
})

0 commit comments

Comments
 (0)