Skip to content

Commit a86404b

Browse files
committed
use new prop binding type indicator syntax
1 parent b0c4d3a commit a86404b

File tree

4 files changed

+131
-24
lines changed

4 files changed

+131
-24
lines changed

examples/modal/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
<div id="app">
5858
<button id="show-modal" on-click="showModal = true">Show Modal</button>
5959
<!-- use the modal component, pass in the prop -->
60-
<modal :show="@showModal">
60+
<modal bind-show@="showModal">
6161
<!--
6262
you can use custom content here to overwrite
6363
default content

src/compiler/compile-props.js

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -102,32 +102,35 @@ module.exports = function compileProps (el, propOptions) {
102102
}
103103
}
104104
} else {
105-
// new syntax
106-
value = prop.raw = _.getBindAttr(el, attr)
105+
// new syntax, check binding type
106+
if ((value = _.getBindAttr(el, attr)) === null) {
107+
if ((value = _.getBindAttr(el, attr + '@')) !== null) {
108+
prop.mode = propBindingModes.TWO_WAY
109+
} else if ((value = _.getBindAttr(el, attr + '*')) !== null) {
110+
prop.mode = propBindingModes.ONE_TIME
111+
}
112+
}
113+
prop.raw = value
107114
if (value !== null) {
108115
// mark it so we know this is a bind
109116
prop.bindSyntax = true
110117
parsed = dirParser.parse(value)
111118
value = parsed.expression
112119
prop.filters = parsed.filters
113-
// check binding type
120+
// check literal
114121
if (literalValueRE.test(value)) {
115122
prop.mode = propBindingModes.ONE_TIME
116123
} else {
117124
prop.dynamic = true
118-
if (value.charAt(0) === '*') {
119-
prop.mode = propBindingModes.ONE_TIME
120-
value = value.slice(1).trim()
121-
} else if (value.charAt(0) === '@') {
122-
value = value.slice(1).trim()
123-
if (settablePathRE.test(value)) {
124-
prop.mode = propBindingModes.TWO_WAY
125-
} else {
126-
process.env.NODE_ENV !== 'production' && _.warn(
127-
'Cannot bind two-way prop with non-settable ' +
128-
'parent path: ' + value
129-
)
130-
}
125+
// check non-settable path for two-way bindings
126+
if (process.env.NODE_ENV !== 'production' &&
127+
prop.mode === propBindingModes.TWO_WAY &&
128+
!settablePathRE.test(value)) {
129+
prop.mode = propBindingModes.ONE_WAY
130+
_.warn(
131+
'Cannot bind two-way prop with non-settable ' +
132+
'parent path: ' + value
133+
)
131134
}
132135
}
133136
}

test/unit/specs/compiler/compile_spec.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,13 +308,14 @@ if (_.inBrowser) {
308308
{ name: 'testOneTime' },
309309
{ name: 'optimizeLiteral' }
310310
]
311-
el.setAttribute('bind-test-normal', 'a')
312-
el.setAttribute('test-literal', '1')
313-
el.setAttribute('bind-optimize-literal', '1')
314-
el.setAttribute('bind-test-two-way', '@a')
315-
el.setAttribute('bind-two-way-warn', '@a + 1')
316-
el.setAttribute('bind-test-one-time', '*a')
317-
compiler.compileAndLinkProps(vm, el, props)
311+
el.innerHTML = '<div ' +
312+
'bind-test-normal="a" ' +
313+
'test-literal="1" ' +
314+
'bind-optimize-literal="1" ' +
315+
'bind-test-two-way@="a" ' +
316+
'bind-two-way-warn@="a + 1" ' +
317+
'bind-test-one-time*="a"></div>'
318+
compiler.compileAndLinkProps(vm, el.firstChild, props)
318319
expect(vm._bindDir.calls.count()).toBe(3) // skip literal and one time
319320
// literal
320321
expect(vm.testLiteral).toBe(1)

test/unit/specs/directives/prop_spec.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,59 @@ if (_.inBrowser) {
9090
})
9191
})
9292

93+
it('two-way binding (new syntax)', function (done) {
94+
var vm = new Vue({
95+
el: el,
96+
data: {
97+
b: 'B',
98+
test: {
99+
a: 'A'
100+
}
101+
},
102+
template: '<test bind-testt@="test" :bb@="b" :a@=" test.a " v-ref="child"></test>',
103+
components: {
104+
test: {
105+
props: ['testt', 'bb', 'a'],
106+
template: '{{testt.a}} {{bb}} {{a}}'
107+
}
108+
}
109+
})
110+
expect(el.firstChild.textContent).toBe('A B A')
111+
vm.test.a = 'AA'
112+
vm.b = 'BB'
113+
_.nextTick(function () {
114+
expect(el.firstChild.textContent).toBe('AA BB AA')
115+
vm.test = { a: 'AAA' }
116+
_.nextTick(function () {
117+
expect(el.firstChild.textContent).toBe('AAA BB AAA')
118+
vm.$data = {
119+
b: 'BBB',
120+
test: {
121+
a: 'AAAA'
122+
}
123+
}
124+
_.nextTick(function () {
125+
expect(el.firstChild.textContent).toBe('AAAA BBB AAAA')
126+
// test two-way
127+
vm.$.child.bb = 'B'
128+
vm.$.child.testt = { a: 'A' }
129+
_.nextTick(function () {
130+
expect(el.firstChild.textContent).toBe('A B A')
131+
expect(vm.test.a).toBe('A')
132+
expect(vm.test).toBe(vm.$.child.testt)
133+
expect(vm.b).toBe('B')
134+
vm.$.child.a = 'Oops'
135+
_.nextTick(function () {
136+
expect(el.firstChild.textContent).toBe('Oops B Oops')
137+
expect(vm.test.a).toBe('Oops')
138+
done()
139+
})
140+
})
141+
})
142+
})
143+
})
144+
})
145+
93146
it('$data as prop', function (done) {
94147
var vm = new Vue({
95148
el: el,
@@ -136,6 +189,28 @@ if (_.inBrowser) {
136189
})
137190
})
138191

192+
it('explicit one time binding (new syntax)', function (done) {
193+
var vm = new Vue({
194+
el: el,
195+
data: {
196+
b: 'B'
197+
},
198+
template: '<test $.child :b*="b"></test>',
199+
components: {
200+
test: {
201+
props: ['b'],
202+
template: '{{b}}'
203+
}
204+
}
205+
})
206+
expect(el.innerHTML).toBe('<test>B</test>')
207+
vm.b = 'BB'
208+
_.nextTick(function () {
209+
expect(el.innerHTML).toBe('<test>B</test>')
210+
done()
211+
})
212+
})
213+
139214
it('non-settable parent path', function (done) {
140215
var vm = new Vue({
141216
el: el,
@@ -164,6 +239,34 @@ if (_.inBrowser) {
164239
})
165240
})
166241

242+
it('non-settable parent path (new syntax)', function (done) {
243+
var vm = new Vue({
244+
el: el,
245+
data: {
246+
b: 'B'
247+
},
248+
template: '<test :b@="b + \'B\'" v-ref="child"></test>',
249+
components: {
250+
test: {
251+
props: ['b'],
252+
template: '{{b}}'
253+
}
254+
}
255+
})
256+
expect(hasWarned(_, 'Cannot bind two-way prop with non-settable parent path')).toBe(true)
257+
expect(el.innerHTML).toBe('<test>BB</test>')
258+
vm.b = 'BB'
259+
_.nextTick(function () {
260+
expect(el.innerHTML).toBe('<test>BBB</test>')
261+
vm.$.child.b = 'hahaha'
262+
_.nextTick(function () {
263+
expect(vm.b).toBe('BB')
264+
expect(el.innerHTML).toBe('<test>hahaha</test>')
265+
done()
266+
})
267+
})
268+
})
269+
167270
it('warn invalid keys', function () {
168271
new Vue({
169272
el: el,

0 commit comments

Comments
 (0)