Skip to content

Commit

Permalink
improve prop default value handling (close #1032)
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jul 10, 2015
1 parent 0d3b264 commit 145fed7
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 6 deletions.
37 changes: 32 additions & 5 deletions src/compiler/compile-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,7 @@ function makePropsLinkFn (props) {
options = prop.options
if (prop.raw === null) {
// initialize absent prop
vm._data[path] = options.type === Boolean
? false
: options.hasOwnProperty('default')
? options.default
: undefined
_.initProp(vm, prop, getDefault(options))
} else if (prop.dynamic) {
// dynamic prop
if (vm._context) {
Expand Down Expand Up @@ -139,3 +135,34 @@ function makePropsLinkFn (props) {
}
}
}

/**
* Get the default value of a prop.
*
* @param {Object} options
* @return {*}
*/

function getDefault (options) {
// absent boolean value
if (options.type === Boolean) {
return false
}
// no default, return undefined
if (!options.hasOwnProperty('default')) {
return
}
var def = options.default
// warn against non-factory defaults for Object & Array
if (_.isObject(def)) {
process.env.NODE_ENV !== 'production' && _.warn(
'Object/Array as default prop values will be shared ' +
'across multiple instances. Use a factory function ' +
'to return the default value instead.'
)
}
// call factory function for non-Function types
return typeof def === 'function' && options.type !== Function
? def()
: def
}
17 changes: 16 additions & 1 deletion test/unit/specs/compiler/compile_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,15 @@ if (_.inBrowser) {
{
name: 'boolean-absent',
type: Boolean
},
{
name: 'factory',
type: Object,
default: function () {
return {
a: 123
}
}
}
].map(function (p) {
return typeof p === 'string' ? { name: p } : p
Expand Down Expand Up @@ -219,7 +228,7 @@ if (_.inBrowser) {
expect(args[3]).toBe(def)
// literal and one time should've been set on the _data
// and numbers should be casted
expect(Object.keys(vm._data).length).toBe(8)
expect(Object.keys(vm._data).length).toBe(9)
expect(vm.a).toBe(1)
expect(vm._data.a).toBe(1)
expect(vm.someOtherAttr).toBe(2)
Expand All @@ -228,10 +237,16 @@ if (_.inBrowser) {
expect(vm._data.onetime).toBe('from parent: a')
expect(vm.booleanLiteral).toBe('from parent: true')
expect(vm._data.booleanLiteral).toBe('from parent: true')
expect(vm.camelCase).toBe('hi')
expect(vm._data.camelCase).toBe('hi')
expect(vm.defaultValue).toBe(123)
expect(vm._data.defaultValue).toBe(123)
expect(vm.boolean).toBe(true)
expect(vm._data.boolean).toBe(true)
expect(vm.booleanAbsent).toBe(false)
expect(vm._data.booleanAbsent).toBe(false)
expect(vm.factory).toBe(vm._data.factory)
expect(vm.factory.a).toBe(123)
})

it('props on root instance', function () {
Expand Down
18 changes: 18 additions & 0 deletions test/unit/specs/directives/prop_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,24 @@ if (_.inBrowser) {
expect(hasWarned(_, 'Props will not be compiled if no `el`')).toBe(true)
})

it('warn object/array default values', function () {
new Vue({
el: el,
props: {
arr: {
type: Array,
default: []
},
obj: {
type: Object,
default: {}
}
}
})
expect(hasWarned(_, 'Use a factory function to return the default value')).toBe(true)
expect(_.warn.calls.count()).toBe(2)
})

it('teardown', function (done) {
var vm = new Vue({
el: el,
Expand Down

0 comments on commit 145fed7

Please sign in to comment.