Skip to content

Commit efcaad1

Browse files
committed
make sure a vm and its data are properly removed from Array when $destroy is called directly
1 parent e37b151 commit efcaad1

File tree

5 files changed

+36
-16
lines changed

5 files changed

+36
-16
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
## Introduction
88

9-
Vue.js is a library for building interactive web interfaces. It provides the benefits of MVVM data binding with a simple and flexible API. You should try it out if you like:
9+
Vue.js is a library for building interactive web interfaces. It provides the benefits of MVVM data binding and a composable component system with a simple and flexible API. You should try it out if you like:
1010

1111
- Extendable Data bindings
1212
- Plain JavaScript objects as models

src/compiler.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,10 @@ CompilerProto.parseDeps = function () {
639639
*/
640640
CompilerProto.destroy = function () {
641641

642+
// avoid being called more than once
643+
// this is irreversible!
644+
if (this.destroyed) return
645+
642646
var compiler = this,
643647
i, key, dir, instances, binding,
644648
vm = compiler.vm,
@@ -697,6 +701,7 @@ CompilerProto.destroy = function () {
697701
vm.$remove()
698702
}
699703

704+
this.destroyed = true
700705
// emit destroy hook
701706
compiler.execHook('afterDestroy')
702707

src/directives/repeat.js

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ module.exports = {
107107
var method = mutation.method
108108
mutationHandlers[method].call(self, mutation)
109109
if (method !== 'push' && method !== 'pop') {
110-
self.updateIndexes()
110+
self.updateIndex()
111111
}
112112
if (method === 'push' || method === 'unshift' || method === 'splice') {
113113
self.changed()
@@ -169,32 +169,33 @@ module.exports = {
169169
*/
170170
buildItem: function (data, index) {
171171

172-
var node = this.el.cloneNode(true),
173-
ctn = this.container,
172+
var el = this.el.cloneNode(true),
173+
ctn = this.container,
174+
vms = this.vms,
175+
col = this.collection,
174176
ref, item
175177

176178
// append node into DOM first
177179
// so v-if can get access to parentNode
178180
if (data) {
179-
ref = this.vms.length > index
180-
? this.vms[index].$el
181+
ref = vms.length > index
182+
? vms[index].$el
181183
: this.ref
182184
// make sure it works with v-if
183185
if (!ref.parentNode) ref = ref.vue_ref
184186
// process transition info before appending
185-
node.vue_trans = utils.attr(node, 'transition', true)
186-
transition(node, 1, function () {
187-
ctn.insertBefore(node, ref)
187+
el.vue_trans = utils.attr(el, 'transition', true)
188+
transition(el, 1, function () {
189+
ctn.insertBefore(el, ref)
188190
}, this.compiler)
189191
}
190192

191193
item = new this.Ctor({
192-
el: node,
194+
el: el,
193195
data: data,
194196
compilerOptions: {
195197
repeat: true,
196198
repeatIndex: index,
197-
repeatCollection: this.collection,
198199
parentCompiler: this.compiler,
199200
delegator: ctn
200201
}
@@ -205,14 +206,19 @@ module.exports = {
205206
// let's remove it...
206207
item.$destroy()
207208
} else {
208-
this.vms.splice(index, 0, item)
209+
vms.splice(index, 0, item)
210+
// in case `$destroy` is called directly on a repeated vm
211+
// make sure the vm's data is properly removed
212+
item.$compiler.observer.on('hook:afterDestroy', function () {
213+
col.remove(data)
214+
})
209215
}
210216
},
211217

212218
/**
213219
* Update index of each item after a mutation
214220
*/
215-
updateIndexes: function () {
221+
updateIndex: function () {
216222
var i = this.vms.length
217223
while (i--) {
218224
this.vms[i].$data.$index = i

test/functional/fixtures/repeated-items.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html>
22
<html lang="en">
33
<head>
4-
<title>SEED repeated items</title>
4+
<title>Vue.js repeated items</title>
55
<meta charset="utf-8">
66
<script src="../../../dist/vue.js"></script>
77
</head>
@@ -20,7 +20,7 @@
2020
</p>
2121
<p>Total items: <span class="count" v-text="items.length"></span></p>
2222
<ul>
23-
<li class="item" v-repeat="items">
23+
<li class="item" v-repeat="items" v-on="click:this.$destroy()">
2424
{{$index}} {{title}}
2525
</li>
2626
</ul>

test/functional/specs/repeated-items.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
casper.test.begin('Repeated Items', 41, function (test) {
1+
/* global items */
2+
3+
casper.test.begin('Repeated Items', 44, function (test) {
24

35
casper
46
.start('./fixtures/repeated-items.html')
@@ -81,6 +83,13 @@ casper.test.begin('Repeated Items', 41, function (test) {
8183
test.assertSelectorHasText('.item:nth-child(1)', '0 6')
8284
test.assertSelectorHasText('.item:nth-child(2)', '1 7')
8385
})
86+
.thenClick('.item:nth-child(1)', function () {
87+
test.assertSelectorHasText('.count', '1')
88+
test.assertSelectorHasText('.item:nth-child(1)', '0 7')
89+
test.assertEval(function () {
90+
return items.length === 1 && items[0].title === '7'
91+
})
92+
})
8493
.run(function () {
8594
test.done()
8695
})

0 commit comments

Comments
 (0)