vue: v-model does not sync when browser autocompletes

Version

2.2.4

Reproduction link

https://martar.fr/demo-vue.html

Steps to reproduce

  • Use the following snippet:
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
    <form @submit.prevent="doSomething()">
        <input type="email" v-model="email" name="email">
        <input type="password" name="password">
        <input type="submit" value="send">
    </form>

    {{ email }}
</div>

<script type="text/javascript">
  new Vue({
    el: '#app',
    data: {
      email: ''
    },
    method: {
      doSomething() {
        alert(this.email)
      }
    }
  })
</script>
  • Go to Chrome Mobile
  • Begin to tap an email
  • Choose an email from Chrome list
  • See that v-model did not work

Here some screenshots of the problem:

Step 1

What is expected?

v-model is supposed to be updated on autoupdate

What is actually happening?

the model is not updated


About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 28 (10 by maintainers)

Commits related to this issue

Most upvoted comments

@scottbedard

I’ve been struggling with this same issue myself. Indeed, I found this to be a serious issue that undermines basic usability. My solutions to this was to enforce the field to be set after a blur event. The problem is that Chrome won’t trigger the input NOR the change events upon adding content to the field. It will however still update the value of the target correctly. Hence, you can try this to see if it works for you:

<template>
    <input v-model="email"
           type='email'
           @blur="onBlur" />
</template>

<script>
export default {
  data () {
    return {
      email: null
    }
  },
  methods: {
    onBlur (event) {
      if (event && this.email !== event.target.value) this.email = event.target.value
    }
}
</script>

Still happening for me.

I decided to simply go back to basic html element access when I’m ready to consume values. Autofill seems to work on desktop and mobile browsers. (I only tried Chrome and Safari)

<input ref="email" v-model="email"/>

// in my function that actually consumes the value I assign whats in the actual element to the model since Vue isn't doing it. 

doLogin() { //my vue method
    this.email=this.$refs.email.$el.value;
    // do really creative stuff
}

I was still having this problem with my Vue project as of May 8th, 2018. iOS 11’s native autofill does not trigger Vue models to update. As a workaround, I wrote a directive to update the Vue model for all inputs on a form when an input receives the Javascript native ‘onfocus’ event (because iOS autofill triggers the onfocus event). I’ll share the code below. Feel free to improve on it or include it on your project.

autofill-catch.js (directive):

export default {
	bind: function (el, binding, vnode) {
		let children = vnode.children;
		children.forEach(child => {
			if (child.tag === 'input') {
				child.elm.onfocus = function () {
					setTimeout(function () {
						updateAllInputs(vnode);
					});
				};
			}
		});
	}
}
function updateAllInputs(vnode) {
	vnode.children.forEach(child => {
		if (child.tag === 'input') {
			vnode.context[child.data.directives['0'].expression] = child.elm.value;
		}
	});
}

Form template (notice the v-autofill-catch directive on my form element):

	  <form v-autofill-catch name="login" v-on:submit.prevent="login([email_address, password])">
		<input v-model="email_address" type="text" name="email_address" placeholder="Email Address">
		<input v-model="password" type="password" placeholder="Password">
		<button type="submit">Login!</button>
	  </form>

main.js, where I’ve included the directive globally in my project:

import autofillCatch from "./directives/autofill-catch.js";
Vue.directive("autofill-catch", autofillCatch);

I can reproduce on iOS 10.2.1, Chrome 57.0.2987.100