Skip to content

Commit d58c7e4

Browse files
committed
v-for: call detached hook for instances in removed fragments (fix vuejs#1440)
1 parent 207c8f0 commit d58c7e4

File tree

4 files changed

+63
-21
lines changed

4 files changed

+63
-21
lines changed

src/directives/for.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ module.exports = {
154154
frag = oldFrags[i]
155155
if (!frag.reused) {
156156
this.deleteCachedFrag(frag)
157-
frag.destroy()
158157
this.remove(frag, removalIndex++, totalRemoved, inDoc)
159158
}
160159
}
@@ -321,11 +320,11 @@ module.exports = {
321320
if (inDoc && staggerAmount) {
322321
var op = frag.staggerCb = _.cancellable(function () {
323322
frag.staggerCb = null
324-
frag.remove()
323+
frag.remove(true)
325324
})
326325
setTimeout(op, staggerAmount)
327326
} else {
328-
frag.remove()
327+
frag.remove(true)
329328
}
330329
},
331330

src/directives/if.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ module.exports = {
4040

4141
insert: function () {
4242
if (this.elseFrag) {
43-
this.elseFrag.remove()
44-
this.elseFrag.destroy()
43+
this.elseFrag.remove(true)
4544
this.elseFrag = null
4645
}
4746
this.frag = this.factory.create(this._host, this._scope, this._frag)
@@ -50,8 +49,7 @@ module.exports = {
5049

5150
remove: function () {
5251
if (this.frag) {
53-
this.frag.remove()
54-
this.frag.destroy()
52+
this.frag.remove(true)
5553
this.frag = null
5654
}
5755
if (this.elseFactory) {

src/fragment/fragment.js

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -83,33 +83,36 @@ function singleBefore (target, trans) {
8383

8484
/**
8585
* Remove fragment, single node version
86+
*
87+
* @param {Boolean} [destroy]
8688
*/
8789

88-
function singleRemove () {
90+
function singleRemove (destroy) {
8991
var shouldCallRemove = _.inDoc(this.node)
90-
transition.remove(this.node, this.vm)
91-
this.inserted = false
92-
if (shouldCallRemove) {
93-
this.callHook(detach)
94-
}
92+
var self = this
93+
transition.remove(this.node, this.vm, function () {
94+
self.inserted = false
95+
if (shouldCallRemove) {
96+
self.callHook(detach)
97+
}
98+
if (destroy) {
99+
self.destroy()
100+
}
101+
})
95102
}
96103

97104
/**
98105
* Insert fragment before target, multi-nodes version
99106
*
100107
* @param {Node} target
101-
* @param {Boolean} trans
102108
*/
103109

104-
function multiBefore (target, trans) {
110+
function multiBefore (target) {
105111
_.before(this.node, target)
106112
var nodes = this.nodes
107113
var vm = this.vm
108-
var method = trans !== false
109-
? transition.before
110-
: _.before
111114
for (var i = 0, l = nodes.length; i < l; i++) {
112-
method(nodes[i], target, vm)
115+
_.before(nodes[i], target, vm)
113116
}
114117
_.before(this.end, target)
115118
this.inserted = true
@@ -120,9 +123,11 @@ function multiBefore (target, trans) {
120123

121124
/**
122125
* Remove fragment, multi-nodes version
126+
*
127+
* @param {Boolean} [destroy]
123128
*/
124129

125-
function multiRemove () {
130+
function multiRemove (destroy) {
126131
var shouldCallRemove = _.inDoc(this.node)
127132
var parent = this.node.parentNode
128133
var node = this.node.nextSibling
@@ -132,7 +137,7 @@ function multiRemove () {
132137
while (node !== this.end) {
133138
nodes.push(node)
134139
next = node.nextSibling
135-
transition.remove(node, vm)
140+
parent.removeChild(node, vm)
136141
node = next
137142
}
138143
parent.removeChild(this.node)
@@ -141,6 +146,9 @@ function multiRemove () {
141146
if (shouldCallRemove) {
142147
this.callHook(detach)
143148
}
149+
if (destroy) {
150+
this.destroy()
151+
}
144152
}
145153

146154
/**

test/unit/specs/directives/for/for_spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,43 @@ if (_.inBrowser) {
774774
})
775775
})
776776

777+
it('call attach/detach for contained components', function (done) {
778+
document.body.appendChild(el)
779+
var attachSpy = jasmine.createSpy('attach')
780+
var detachSpy = jasmine.createSpy('detach')
781+
var vm = new Vue({
782+
el: el,
783+
template: '<test v-for="item in items"></test>',
784+
data: {
785+
items: [1, 2]
786+
},
787+
components: {
788+
test: {
789+
attached: attachSpy,
790+
detached: detachSpy
791+
}
792+
}
793+
})
794+
expect(attachSpy.calls.count()).toBe(2)
795+
expect(detachSpy.calls.count()).toBe(0)
796+
vm.items.push(3)
797+
_.nextTick(function () {
798+
expect(attachSpy.calls.count()).toBe(3)
799+
expect(detachSpy.calls.count()).toBe(0)
800+
vm.items.pop()
801+
_.nextTick(function () {
802+
expect(attachSpy.calls.count()).toBe(3)
803+
expect(detachSpy.calls.count()).toBe(1)
804+
vm.items = []
805+
_.nextTick(function () {
806+
expect(attachSpy.calls.count()).toBe(3)
807+
expect(detachSpy.calls.count()).toBe(3)
808+
done()
809+
})
810+
})
811+
})
812+
})
813+
777814
})
778815
}
779816

0 commit comments

Comments
 (0)