Skip to content

Commit e879b8f

Browse files
committed
v-for: call detached hook for instances in removed fragments (fix vuejs#1440)
1 parent 02655cd commit e879b8f

File tree

4 files changed

+63
-21
lines changed

4 files changed

+63
-21
lines changed

src/directives/public/for.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ module.exports = {
145145
frag = oldFrags[i]
146146
if (!frag.reused) {
147147
this.deleteCachedFrag(frag)
148-
frag.destroy()
149148
this.remove(frag, removalIndex++, totalRemoved, inDoc)
150149
}
151150
}
@@ -313,11 +312,11 @@ module.exports = {
313312
if (inDoc && staggerAmount) {
314313
var op = frag.staggerCb = _.cancellable(function () {
315314
frag.staggerCb = null
316-
frag.remove()
315+
frag.remove(true)
317316
})
318317
setTimeout(op, staggerAmount)
319318
} else {
320-
frag.remove()
319+
frag.remove(true)
321320
}
322321
},
323322

src/directives/public/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
@@ -87,33 +87,36 @@ function singleBefore (target, trans) {
8787

8888
/**
8989
* Remove fragment, single node version
90+
*
91+
* @param {Boolean} [destroy]
9092
*/
9193

92-
function singleRemove () {
94+
function singleRemove (destroy) {
9395
var shouldCallRemove = _.inDoc(this.node)
94-
transition.remove(this.node, this.vm)
95-
this.inserted = false
96-
if (shouldCallRemove) {
97-
this.callHook(detach)
98-
}
96+
var self = this
97+
transition.remove(this.node, this.vm, function () {
98+
self.inserted = false
99+
if (shouldCallRemove) {
100+
self.callHook(detach)
101+
}
102+
if (destroy) {
103+
self.destroy()
104+
}
105+
})
99106
}
100107

101108
/**
102109
* Insert fragment before target, multi-nodes version
103110
*
104111
* @param {Node} target
105-
* @param {Boolean} trans
106112
*/
107113

108-
function multiBefore (target, trans) {
114+
function multiBefore (target) {
109115
_.before(this.node, target)
110116
var nodes = this.nodes
111117
var vm = this.vm
112-
var method = trans !== false
113-
? transition.before
114-
: _.before
115118
for (var i = 0, l = nodes.length; i < l; i++) {
116-
method(nodes[i], target, vm)
119+
_.before(nodes[i], target, vm)
117120
}
118121
_.before(this.end, target)
119122
this.inserted = true
@@ -124,9 +127,11 @@ function multiBefore (target, trans) {
124127

125128
/**
126129
* Remove fragment, multi-nodes version
130+
*
131+
* @param {Boolean} [destroy]
127132
*/
128133

129-
function multiRemove () {
134+
function multiRemove (destroy) {
130135
var shouldCallRemove = _.inDoc(this.node)
131136
var parent = this.node.parentNode
132137
var node = this.node.nextSibling
@@ -136,7 +141,7 @@ function multiRemove () {
136141
while (node !== this.end) {
137142
nodes.push(node)
138143
next = node.nextSibling
139-
transition.remove(node, vm)
144+
parent.removeChild(node, vm)
140145
node = next
141146
}
142147
parent.removeChild(this.node)
@@ -145,6 +150,9 @@ function multiRemove () {
145150
if (shouldCallRemove) {
146151
this.callHook(detach)
147152
}
153+
if (destroy) {
154+
this.destroy()
155+
}
148156
}
149157

150158
/**

test/unit/specs/directives/public/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)