@@ -380,37 +380,68 @@ describe('Directive v-model text', () => {
380
380
} )
381
381
382
382
// #6552
383
- // This was original introduced due to the microtask between DOM events issue
384
- // but fixed after switching to MessageChannel.
383
+ // Root cause: input listeners with modifiers are added as a separate
384
+ // DOM listener. If a change is triggered inside this listener, an update
385
+ // will happen before the second listener is fired! (obviously microtasks
386
+ // can be processed in between DOM events on the same element)
387
+ // This causes the domProps module to receive state that has not been
388
+ // updated by v-model yet (because v-model's listener has not fired yet)
389
+ // Solution: make sure to always fire v-model's listener first
390
+ // #11925
391
+ // After fix #11925, input event should trigger an update after two listener,
392
+ // not after the first listener, before the second listener.
393
+ // So we should also test whether the v-model listener is triggered
394
+ // before the listener with once modifier by the variable vModelTriggerBeforeOnce.
385
395
it ( 'should not block input when another input listener with modifier is used' , done => {
396
+ let vModelTriggerBeforeOnce = false
397
+ const captureInputValue = 'b'
398
+ const onceInputValue = 'x'
386
399
const vm = new Vue ( {
387
400
data : {
388
401
a : 'a' ,
389
- foo : false
402
+ foo : false ,
403
+ b : 'b' ,
404
+ bar : false ,
390
405
} ,
391
406
template : `
392
- <div>
393
- <input ref="input" v-model="a" @input.capture="onInput">{{ a }}
394
- <div v-if="foo">foo</div>
395
- </div>
396
- ` ,
407
+ <div>
408
+ <input ref="input" v-model="a" @input.capture="onInput">{{ a }}
409
+ <div v-if="foo">foo</div>
410
+ <input ref="onceInput" v-model="b" @input.once="onInputBar">{{ b }}
411
+ <div v-if="bar">bar</div>
412
+ </div>
413
+ ` ,
397
414
methods : {
398
415
onInput ( e ) {
399
416
this . foo = true
417
+ } ,
418
+ onInputBar ( e ) {
419
+ vModelTriggerBeforeOnce = this . b === onceInputValue
420
+ this . bar = true
400
421
}
401
422
}
402
423
} ) . $mount ( )
403
424
404
425
document . body . appendChild ( vm . $el )
405
426
vm . $refs . input . focus ( )
406
- vm . $refs . input . value = 'b'
427
+ vm . $refs . input . value = captureInputValue
407
428
triggerEvent ( vm . $refs . input , 'input' )
408
429
430
+ vm . $refs . onceInput . focus ( )
431
+ vm . $refs . onceInput . value = onceInputValue
432
+ triggerEvent ( vm . $refs . onceInput , 'input' )
433
+
409
434
// not using wait for update here because there will be two update cycles
410
435
// one caused by onInput in the first listener
411
436
setTimeout ( ( ) => {
412
- expect ( vm . a ) . toBe ( 'b' )
413
- expect ( vm . $refs . input . value ) . toBe ( 'b' )
437
+ expect ( vm . a ) . toBe ( captureInputValue )
438
+ expect ( vm . foo ) . toBe ( true )
439
+ expect ( vm . $refs . input . value ) . toBe ( captureInputValue )
440
+
441
+ expect ( vm . b ) . toBe ( onceInputValue )
442
+ expect ( vm . bar ) . toBe ( true )
443
+ expect ( vm . $refs . onceInput . value ) . toBe ( onceInputValue )
444
+ expect ( vModelTriggerBeforeOnce ) . toBe ( true )
414
445
done ( )
415
446
} , 16 )
416
447
} )
0 commit comments