Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix $refs updating #3217

Merged
merged 1 commit into from
Jul 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/compiler/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -665,8 +665,8 @@ function makeTerminalNodeLinkFn (el, dirName, value, options, def, rawName, arg,
modifiers: modifiers,
def: def
}
// check ref for v-for and router-view
if (dirName === 'for' || dirName === 'router-view') {
// check ref for v-for, v-if and router-view
if (dirName === 'for' || dirName === 'if' || dirName === 'router-view') {
descriptor.ref = findRef(el)
}
var fn = function terminalNodeLinkFn (vm, el, host, scope, frag) {
Expand Down
21 changes: 2 additions & 19 deletions src/directives/public/for.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
def,
cancellable,
isArray,
isPlainObject
isPlainObject,
findVmFromFrag
} from '../../util/index'

let uid = 0
Expand Down Expand Up @@ -602,24 +603,6 @@ function findPrevFrag (frag, anchor, id) {
return frag
}

/**
* Find a vm from a fragment.
*
* @param {Fragment} frag
* @return {Vue|undefined}
*/

function findVmFromFrag (frag) {
let node = frag.node
// handle multi-node frag
if (frag.end) {
while (!node.__vue__ && node !== frag.end && node.nextSibling) {
node = node.nextSibling
}
}
return node.__vue__
}

/**
* Create a range array from given number.
*
Expand Down
28 changes: 27 additions & 1 deletion src/directives/public/if.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
remove,
replace,
createAnchor,
warn
warn,
findVmFromFrag
} from '../../util/index'

export default {
Expand Down Expand Up @@ -40,8 +41,10 @@ export default {
if (value) {
if (!this.frag) {
this.insert()
this.updateRef(value)
}
} else {
this.updateRef(value)
this.remove()
}
},
Expand Down Expand Up @@ -76,6 +79,29 @@ export default {
}
},

updateRef (value) {
var ref = this.descriptor.ref
if (!ref) return
var hash = (this.vm || this._scope).$refs
var refs = hash[ref]
var key = this._frag.scope.$key
if (!refs) return
if (value) {
if (Array.isArray(refs)) {
refs.push(findVmFromFrag(this._frag))
} else {
refs[key] = findVmFromFrag(this._frag)
}
} else {
if (Array.isArray(refs)) {
refs.$remove(findVmFromFrag(this._frag))
} else {
refs[key] = null
delete refs[key]
}
}
},

unbind () {
if (this.frag) {
this.frag.destroy()
Expand Down
18 changes: 18 additions & 0 deletions src/util/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,21 @@ export function getOuterHTML (el) {
return container.innerHTML
}
}

/**
* Find a vm from a fragment.
*
* @param {Fragment} frag
* @return {Vue|undefined}
*/

export function findVmFromFrag (frag) {
let node = frag.node
// handle multi-node frag
if (frag.end) {
while (!node.__vue__ && node !== frag.end && node.nextSibling) {
node = node.nextSibling
}
}
return node.__vue__
}
73 changes: 73 additions & 0 deletions test/unit/specs/directives/public/if_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,4 +432,77 @@ describe('v-if', function () {
done()
})
})

// GitHub issue #3204
it('update array refs', function (done) {
var vm = new Vue({
el: el,
template: '<foo v-if="!activeItem || $index === activeItem" v-ref:foo :index="$index" v-for="item in items"></foo>',
data: {
items: [0, 1, 2],
activeItem: null
},
components: {
foo: {
props: ['index'],
template: '<div>I am foo ({{ index }})<div>'
}
}
})
vm.$refs.foo.forEach(function (ref, index) {
expect(ref.$el.textContent).toBe('I am foo (' + index + ')')
expect(ref.index).toBe(index)
})
vm.activeItem = 1 // select active item
nextTick(function () {
expect(vm.$refs.foo.length).toBe(1)
expect(vm.$refs.foo[0].index).toBe(1)
vm.activeItem = null // enable all elements
nextTick(function () {
expect(vm.$refs.foo.length).toBe(3)
done()
})
})
})

it('update object refs', function (done) {
var vm = new Vue({
el: el,
template: '<foo v-if="!activeKey || $key === activeKey" v-ref:foo :key="$key" v-for="item in items"></foo>',
data: {
items: {
a: 1,
b: 2,
c: 3
},
activeKey: null
},
components: {
foo: {
props: ['key'],
template: '<div>I am foo ({{ key }})<div>'
}
}
})
Object.keys(vm.$refs.foo).forEach(function (key) {
var ref = vm.$refs.foo[key]
expect(ref.$el.textContent).toBe('I am foo (' + key + ')')
expect(ref.key).toBe(key)
})
vm.activeKey = 'b' // select active item
nextTick(function () {
expect(Object.keys(vm.$refs.foo).length).toBe(1)
expect(vm.$refs.foo['b'].key).toBe('b')
vm.activeKey = null // enable all elements
nextTick(function () {
expect(Object.keys(vm.$refs.foo).length).toBe(3)
Object.keys(vm.$refs.foo).forEach(function (key) {
var ref = vm.$refs.foo[key]
expect(ref.$el.textContent).toBe('I am foo (' + key + ')')
expect(ref.key).toBe(key)
})
done()
})
})
})
})