Skip to content

Commit 838c98a

Browse files
committed
avoid overwriting inherited properties when initializing props (fix vuejs#1012)
1 parent e087e58 commit 838c98a

File tree

7 files changed

+102
-68
lines changed

7 files changed

+102
-68
lines changed

src/compiler/compile-props.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,7 @@ function makePropsLinkFn (props) {
111111
if (prop.mode === propBindingModes.ONE_TIME) {
112112
// one time binding
113113
value = vm._context.$get(prop.parentPath)
114-
if (_.assertProp(prop, value)) {
115-
vm[path] = vm._data[path] = value
116-
}
114+
_.initProp(vm, prop, value)
117115
} else {
118116
// dynamic binding
119117
vm._bindDir('prop', el, prop, propDef)
@@ -130,9 +128,7 @@ function makePropsLinkFn (props) {
130128
value = options.type === Boolean && prop.raw === ''
131129
? true
132130
: _.toBoolean(_.toNumber(prop.raw))
133-
if (_.assertProp(prop, value)) {
134-
vm[path] = vm._data[path] = value
135-
}
131+
_.initProp(vm, prop, value)
136132
}
137133
}
138134
}

src/directives/prop.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,10 @@ module.exports = {
4848
// !!! We need to set it also on raw data here, because
4949
// props are initialized before data is fully observed
5050
var value = this.parentWatcher.value
51-
if (_.assertProp(prop, value)) {
52-
if (childKey === '$data') {
53-
child._data = value
54-
} else {
55-
child[childKey] = child._data[childKey] = value
56-
}
51+
if (childKey === '$data') {
52+
child._data = value
53+
} else {
54+
_.initProp(child, prop, value)
5755
}
5856

5957
// only setup two-way binding if this is not a one-way

src/util/misc.js renamed to src/util/component.js

Lines changed: 51 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,55 @@
11
var _ = require('./index')
2-
var config = require('../config')
2+
3+
/**
4+
* Check if an element is a component, if yes return its
5+
* component id.
6+
*
7+
* @param {Element} el
8+
* @param {Object} options
9+
* @return {String|undefined}
10+
*/
11+
12+
exports.commonTagRE = /^(div|p|span|img|a|br|ul|ol|li|h1|h2|h3|h4|h5|code|pre)$/
13+
exports.checkComponent = function (el, options) {
14+
var tag = el.tagName.toLowerCase()
15+
if (tag === 'component') {
16+
// dynamic syntax
17+
var exp = el.getAttribute('is')
18+
el.removeAttribute('is')
19+
return exp
20+
} else if (
21+
!exports.commonTagRE.test(tag) &&
22+
_.resolveAsset(options, 'components', tag)
23+
) {
24+
return tag
25+
/* eslint-disable no-cond-assign */
26+
} else if (tag = _.attr(el, 'component')) {
27+
/* eslint-enable no-cond-assign */
28+
return tag
29+
}
30+
}
31+
32+
/**
33+
* Set a prop's initial value on a vm and its data object.
34+
* The vm may have inherit:true so we need to make sure
35+
* we don't accidentally overwrite parent value.
36+
*
37+
* @param {Vue} vm
38+
* @param {Object} prop
39+
* @param {*} value
40+
*/
41+
42+
exports.initProp = function (vm, prop, value) {
43+
if (exports.assertProp(prop, value)) {
44+
var key = prop.path
45+
if (key in vm) {
46+
_.define(vm, key, value, true)
47+
} else {
48+
vm[key] = value
49+
}
50+
vm._data[key] = value
51+
}
52+
}
353

454
/**
555
* Assert whether a prop is valid.
@@ -67,56 +117,3 @@ function formatType (val) {
67117
function formatValue (val) {
68118
return Object.prototype.toString.call(val).slice(8, -1)
69119
}
70-
71-
/**
72-
* Check if an element is a component, if yes return its
73-
* component id.
74-
*
75-
* @param {Element} el
76-
* @param {Object} options
77-
* @return {String|undefined}
78-
*/
79-
80-
exports.commonTagRE = /^(div|p|span|img|a|br|ul|ol|li|h1|h2|h3|h4|h5|code|pre)$/
81-
exports.checkComponent = function (el, options) {
82-
var tag = el.tagName.toLowerCase()
83-
if (tag === 'component') {
84-
// dynamic syntax
85-
var exp = el.getAttribute('is')
86-
el.removeAttribute('is')
87-
return exp
88-
} else if (
89-
!exports.commonTagRE.test(tag) &&
90-
_.resolveAsset(options, 'components', tag)
91-
) {
92-
return tag
93-
/* eslint-disable no-cond-assign */
94-
} else if (tag = _.attr(el, 'component')) {
95-
/* eslint-enable no-cond-assign */
96-
return tag
97-
}
98-
}
99-
100-
/**
101-
* Create an "anchor" for performing dom insertion/removals.
102-
* This is used in a number of scenarios:
103-
* - block instance
104-
* - v-html
105-
* - v-if
106-
* - component
107-
* - repeat
108-
*
109-
* @param {String} content
110-
* @param {Boolean} persist - IE trashes empty textNodes on
111-
* cloneNode(true), so in certain
112-
* cases the anchor needs to be
113-
* non-empty to be persisted in
114-
* templates.
115-
* @return {Comment|Text}
116-
*/
117-
118-
exports.createAnchor = function (content, persist) {
119-
return config.debug
120-
? document.createComment(content)
121-
: document.createTextNode(persist ? ' ' : '')
122-
}

src/util/dom.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,27 @@ exports.isTemplate = function (el) {
234234
return el.tagName &&
235235
el.tagName.toLowerCase() === 'template'
236236
}
237+
238+
/**
239+
* Create an "anchor" for performing dom insertion/removals.
240+
* This is used in a number of scenarios:
241+
* - block instance
242+
* - v-html
243+
* - v-if
244+
* - component
245+
* - repeat
246+
*
247+
* @param {String} content
248+
* @param {Boolean} persist - IE trashes empty textNodes on
249+
* cloneNode(true), so in certain
250+
* cases the anchor needs to be
251+
* non-empty to be persisted in
252+
* templates.
253+
* @return {Comment|Text}
254+
*/
255+
256+
exports.createAnchor = function (content, persist) {
257+
return config.debug
258+
? document.createComment(content)
259+
: document.createTextNode(persist ? ' ' : '')
260+
}

src/util/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ var extend = lang.extend
44
extend(exports, lang)
55
extend(exports, require('./env'))
66
extend(exports, require('./dom'))
7-
extend(exports, require('./misc'))
8-
extend(exports, require('./debug'))
97
extend(exports, require('./options'))
8+
extend(exports, require('./component'))
9+
extend(exports, require('./debug'))

test/unit/specs/directives/prop_spec.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,5 +384,24 @@ if (_.inBrowser) {
384384
expect(hasWarned(_, 'Expected Number')).toBe(true)
385385
expect(el.textContent).toBe('AAA')
386386
})
387+
388+
it('should not overwrite inherit:true properties', function () {
389+
var vm = new Vue({
390+
el: el,
391+
data: {
392+
msg: 'hi!'
393+
},
394+
template: '<test msg="ho!"></test>',
395+
components: {
396+
test: {
397+
props: ['msg'],
398+
inherit: true,
399+
template: '{{msg}}'
400+
}
401+
}
402+
})
403+
expect(vm.msg).toBe('hi!')
404+
expect(el.textContent).toBe('ho!')
405+
})
387406
})
388407
}

0 commit comments

Comments
 (0)