Vue: v-model does not sync when browser autocompletes

Created on 21 Mar 2017  路  24Comments  路  Source: vuejs/vue

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


improvement

Most helpful comment

@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>

All 24 comments

Can't reproduce. Not much can be done without repro.

The repro is fine, you need to have used the phone with email inputs already. I tested on Androi 6 and it works just fine. Unfortunately I don't have an iPhone

Tested on iPad safari & chrome. Working as expected.

I updated the reproduction on a self hosted server, so you can access it through https://martar.fr/demo-vue.html

Safari does not seem to reproduce the problem, however, Chrome IOS does it all the time with this code.

I am using Google Chrome 57.0.2987.100 on an Iphone 5 10.2.1

@vuejs/collaborators can anyone confirm this?

@ElMatella It works fine in Safari. Not been using Chrome so don't have a saved email. Can you provide a submittable form, so the email gets saved by Chrome?

I updated the form, so you can submit it https://martar.fr/demo-vue.html

I can reproduce on iOS 10.2.1, Chrome 57.0.2987.100

@ElMatella I recommend you to open the issue on the chrome issue tracker anyway. It's probably an issue with the iOS chrome version not firing the input/change event when autocompleting from keyboard suggestions

Hi @posva thank you for the advice, I went to the chrome issue tracker (the chromium one, I don't even know if this is what I should look for), but I admit that I don't feel very confident with their system, I'm not a huge actor on community devs... But I wonder, if the issue appears on a "stable version" of chrome, should'nt be Vue that should adapt?

Again, I am not used to this... And I am not familiar with Vue core, where are defined the events to listen on inputs changes?

Ok, I updated the snippet I created with this:

<div id="app">
    <form method="get" action="demo-vue.html">
        <input type="email" v-model="email" name="email" @change="saySomething()">
        <input type="submit" value="send">
    </form>

  {{ email }}
</div>
<script type="text/javascript">
    new Vue({
      el: '#app',
      data: {
        email: ''
      },
      methods: {
        saySomething () {
            alert('olas')
        }
      }
    })
</script>

The v-model is only listening for the input event. However, the IOS chrome autocomplete behaviour triggers the change event. So could we not update the data on the change event also?

No, because stable versions do have bugs 馃槃
Yes, it's there where the error should be reported. I personally cannot reproduce it because I don't own an iPhone, and I do not get any autocomplete option in the emulator. To go further you could check if the input emits thechange or input event (this can be done with vanilla js) when autocompleting and check if the behaviour is different from ios chrome to a desktop chrome. If it is, then you should report the bug in the chromium issue tracker https://bugs.chromium.org/p/chromium/issues/list

Ok, I submitted an issue: https://bugs.chromium.org/p/chromium/issues/detail?id=705275#

In the meantime, I am going to manually listen on the change event to update model... I keep you informed of Chrome team responses, thank you :)

I didn't see the comment above before commenting (it didn't sync). Listening for change and input will have a perf impact when dealing with many v-model with inputs, so I wonder if it's good to listen for both. On the other hand, it should work. Maybe a check for iOS Chrome can prevent that

Yes, it would have an impact on perf, however, the change event is not triggered as much as the input event, only once when user unfocus the input.

It's not because of twice the amount of triggers, adding more event listeners do have an extra cost too

I don't know if i'm alone in that case, but this issue is still happening on Safari 11.0

  • Autofill is running fine on Safari 11.0 (when you click on the little guy in an input and you select in the list which one)
  • But autocomplete after a first passed form submit don't work on Safari 11.0 (when you start tipping, and you immediately click on the list)

The issue is the component is not updated properly and data transmit are not updated. Exemple:

  1. You write 'OKBOYS' on first time and you submit, the form must be valid to be cached by Safari.
  2. Reload the page by the browser (CMD + R).
  3. You start writting 'OK' for the second time, Safari offers you to select 'OKBOYS' in the list bellow the input. You select it. The graphical input value is 'OKBOYS' but the real value transmitted is still only what you tipped 'OK'.

autocomplete="nope" or autocomplete="off" (cf here) don't change anything. Safari seams to ignore this html attribute and offers autocompletion; not other Web Browser (Edge, Chrome, FF).

EDIT: autocomplete="off" works in fact. The way i was still getting an error was caused by Safari form cache (i juste erase form autofill cache in Safari preferences). So autocomplete="off" is just a bypass to this issue, but the issue still present for me.

the component which reproduce this issue

Still happening for me.

I tried listening to the change event, but I wasn't able to work around the bug. Any one has experience trying to work around this? The bug is still happening on iOS 11.3 + iOS Chrome App v66.0.3359.122 for me.

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 also confirm on Vue 2.9.6 using android chrome 67.0.3396.87.

None of the html attributes that are supposed to stop autocomplete and suggested words work. Chrome seems to just ignore them.

The above fix for iOS doesn't seem to work for Chrome on android.

My current problem is that when I tap a submit button on a form the model is empty because of autocomplete problems. However, if the input loses focus the model seems to update. I therefore tried a programatic blurring, but that didn't work, so now I have a 30ms timeout after I tap the button before doing anything with the model. This won't solve everyones problems but maybe a few :-)

Unfortunately jordancaudill's solution did not work for me, my signin page is still unuseable on iOS chrome. Are there any other work arounds to this problem?

@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>

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
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wufeng87 picture wufeng87  路  3Comments

julianxhokaxhiu picture julianxhokaxhiu  路  3Comments

aviggngyv picture aviggngyv  路  3Comments

gkiely picture gkiely  路  3Comments

paulpflug picture paulpflug  路  3Comments