vue icon indicating copy to clipboard operation
vue copied to clipboard

<input> rerenders while changes affects only sibling elements

Open kamax1 opened this issue 8 years ago • 17 comments

Version

2.5.2

Reproduction link

https://codepen.io/anon/pen/OxKqbL?editors=1111

Steps to reproduce

Please open codepen example and type something into input

What is expected?

Input should not lose focus

What is actually happening?

input rerenders and loses focus


happens only if there is such conditional elements exists before and after input. Workaround is to use v-show instead of v-if in such cases.

kamax1 avatar Oct 26 '17 10:10 kamax1

You can also simply give the <input> a key to ensure it is not replaced.

yyx990803 avatar Oct 26 '17 16:10 yyx990803

i tried your solution in codepen and still cant get it working.

i tried this <input type="text" v-model="inputVal" :key="1">

kamax1 avatar Oct 26 '17 18:10 kamax1

U need to have same DOM structure before your input. Look this. It can be after update your DOM before your input tag

IlyaOsotov avatar Nov 06 '17 15:11 IlyaOsotov

Actually, it is the same input element, but first remove from the document then move it to other places, for example:

it first renders like

 <!----> // A
<input />
 <!----> // B

then you focus input and input some words, then virtual dom insert <span>before</span>, and it then parent.insertBefore(input, A), it moves the input element before the A comment element, so it will eventually lose focus, then it will delete the comment node.

so, I think you could use v-show better to avoid the insertBefore move problem(remove from the document then insert before the reference node, in this case, which is comment A ). This is the default action for virtual dom of vue which doesn't replace comment node.

kyle7zhang avatar Dec 10 '17 17:12 kyle7zhang

You can also simply give the <input> a key to ensure it is not replaced.

<input> element focus is lost in either case.

znck avatar Dec 11 '17 01:12 znck

https://github.com/google/incremental-dom/issues/237
seems like this one

Kingwl avatar Dec 20 '17 02:12 Kingwl

I have tried to fix this issue
But I encountered some problem have we got some way to access vnode from html element?
I want to get vnode path as https://github.com/google/incremental-dom/issues/237
But I did not find a good way to do that
have i missing something? or have other better solution?😅

Kingwl avatar Jan 03 '18 09:01 Kingwl

@Kingwl you can use v-show. It works correctly.

dev-blinov avatar Jan 13 '19 18:01 dev-blinov

Alternative way: https://codepen.io/furrya_black/pen/ZVVLpQ

Just html-layout usually has a more complex structure. What do you thing? As a proof you can see any css framework: material disign, bulma, bootstrap, etc (what else)

UPD: if your case require rerender-mehanic (with v-if)

furryablack avatar Jan 13 '19 19:01 furryablack

It also seems to break (loose focus) if the spans are shown initially:

https://codepen.io/janschoenherr/pen/NoJpoY?editors=1111

I would think that it doesn't need to do insertBefore in this case.

janschoenherr avatar Feb 19 '19 19:02 janschoenherr

Other reproductions:

https://codepen.io/adamwathan/pen/vMJrYj https://codesandbox.io/s/q9mqnjnxr9

Akryum avatar Apr 14 '19 06:04 Akryum

Thread on twitter

Akryum avatar Apr 14 '19 06:04 Akryum

F.Y.I. It seems that #9473, #9496, #9808 all share the same root cause.

Justineo avatar Apr 14 '19 09:04 Justineo

I'm using Vue 2.6.7 and this issue is still relevant, i was able to work it out by using v-show instead of v-if on a sibling, but it's still confusing why it doesn't work when v-if is used

brnteka avatar Sep 09 '19 13:09 brnteka

I found that @focus is not reliable when using DOM manipulation, such as v-if and therefore, directives would be the best approach:

<template>
    <form method="POST"
          autocomplete="off"
          @submit.prevent="onSubmit">

<!--     We set the directive here v-focus with the function prop handleFocus -->
        <div class="flex mt-1 rounded-md shadow-sm">
            <input id="title"
                   type="text"
                   v-focus="handleFocus"
                   v-model="form.title">
        </div>

    </form>
</template>


<script>
        export default {
            name: "FormComponent",
            data() {
                return {
                    // A form class example, but you could just have a var
                    form: new this.$form({
                        title: null,
                    })
                }
            },
            directives: {
                focus: {
                    inserted(el,binding) {
                        // We set focus on the element
                        el.focus();
                        // optional if you had other operations. Data and props, etc. are not available inside
                        // a direective uless yoru decorate the provider, which is a pain. So we call the binding
                        // which is the handleFocus set on input. We pass the el but we could inject nothing or a event, binding, etc
                        if (!_.isUndefined(binding.value)) binding.value(el)
                    }
                }
            },
            methods: {
                handleFocus: function() {
                    // For example reset a form v-model
                    this.form.title = null;
                },
            }
        }
    </script>

nolros avatar Mar 01 '20 20:03 nolros

v-show it worked thanks.

misaghkarimi avatar Jun 11 '21 16:06 misaghkarimi

I had the problem where a v-if causes the parent modal to lose focus so that pressing <esc> does not close the modal. v-show did not fix my problem since rendering the element when the v-if condition is not met results in an error due to a null value.

I worked around this by focusing an invisible dummy <Input /> in the modal whenever the v-if condition changes.

hljeong avatar Feb 19 '24 12:02 hljeong