Skip to content

Commit

Permalink
Fix: nested child elements can not be updated correctly, fix #5618 (#…
Browse files Browse the repository at this point in the history
…5627)

* fix:nested elements can not be updated correctly

* add tests

* ensure nestedIndex is always passed down
  • Loading branch information
gebilaoxiong authored and yyx990803 committed May 9, 2017
1 parent 5d965d5 commit f2bd882
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 3 deletions.
5 changes: 4 additions & 1 deletion src/core/instance/render-helpers/render-list.js
@@ -1,6 +1,6 @@
/* @flow */

import { isObject } from 'core/util/index'
import { isObject, isDef } from 'core/util/index'

/**
* Runtime helper for rendering v-for lists.
Expand Down Expand Up @@ -28,5 +28,8 @@ export function renderList (
ret[i] = render(val[key], key, i)
}
}
if (isDef(ret)) {
(ret: any)._isVList = true
}
return ret
}
7 changes: 5 additions & 2 deletions src/core/vdom/helpers/normalize-children.js
@@ -1,7 +1,7 @@
/* @flow */

import VNode, { createTextVNode } from 'core/vdom/vnode'
import { isFalse, isDef, isUndef, isPrimitive } from 'shared/util'
import { isFalse, isTrue, isDef, isUndef, isPrimitive } from 'shared/util'

// The template compiler attempts to minimize the need for normalization by
// statically analyzing the template at compile time.
Expand Down Expand Up @@ -58,7 +58,10 @@ function normalizeArrayChildren (children: any, nestedIndex?: string): Array<VNo
res[res.length - 1] = createTextVNode(last.text + c.text)
} else {
// default key for nested array children (likely generated by v-for)
if (isDef(c.tag) && isUndef(c.key) && isDef(nestedIndex)) {
if (isTrue(children._isVList) &&
isDef(c.tag) &&
isUndef(c.key) &&
isDef(nestedIndex)) {
c.key = `__vlist${nestedIndex}_${i}__`
}
res.push(c)
Expand Down
21 changes: 21 additions & 0 deletions test/unit/features/component/component-slot.spec.js
Expand Up @@ -639,4 +639,25 @@ describe('Component slot', () => {
expect(vm.$el.textContent).toBe('2foo')
}).then(done)
})

it('the elements of slot should be updated correctly', done => {
const vm = new Vue({
data: { n: 1 },
template: '<div><test><span v-for="i in n" :key="i">{{ i }}</span><input value="a"/></test></div>',
components: {
test: {
template: '<div><slot></slot></div>'
}
}
}).$mount()
expect(vm.$el.innerHTML).toBe('<div><span>1</span><input value="a"></div>')
const input = vm.$el.querySelector('input')
input.value = 'b'
vm.n++
waitForUpdate(() => {
expect(vm.$el.innerHTML).toBe('<div><span>1</span><span>2</span><input value="a"></div>')
expect(vm.$el.querySelector('input')).toBe(input)
expect(vm.$el.querySelector('input').value).toBe('b')
}).then(done)
})
})
28 changes: 28 additions & 0 deletions test/unit/modules/vdom/create-element.spec.js
Expand Up @@ -152,4 +152,32 @@ describe('create-element', () => {
}).$mount()
expect('Avoid using observed data object as vnode data').toHaveBeenWarned()
})

it('nested child elements should be updated correctly', done => {
const vm = new Vue({
data: { n: 1 },
render (h) {
const list = []
for (let i = 0; i < this.n; i++) {
list.push(h('span', i))
}
const input = h('input', {
attrs: {
value: 'a',
type: 'text'
}
})
return h('div', [[...list, input]])
}
}).$mount()
expect(vm.$el.innerHTML).toBe('<span>0</span><input value="a" type="text">')
const el = vm.$el.querySelector('input')
el.value = 'b'
vm.n++
waitForUpdate(() => {
expect(vm.$el.innerHTML).toBe('<span>0</span><span>1</span><input value="a" type="text">')
expect(vm.$el.querySelector('input')).toBe(el)
expect(vm.$el.querySelector('input').value).toBe('b')
}).then(done)
})
})

0 comments on commit f2bd882

Please sign in to comment.