I have this code: (Note the structure of input
s and label
s and v-if
s and v-else
s)
new window.Vue({
el: "#app",
template: `
<div>
This will reset:
<div v-if="loginType === 'username'">
<label>Username: <input/></label>
</div>
<div v-else>
<label>Email: <input/></label>
</div>
<br />
This will not:
<div v-if="loginType === 'username'">
<label>Username: </label>
<input/>
</div>
<div v-else>
<label>Email: </label>
<input/>
</div>
<br />
This will reset too:
<div v-if="loginType === 'username'">
<label>Username: </label>
<input key="input-for-username"/>
</div>
<div v-else>
<label>Email: </label>
<input key="input-for-email"/>
</div>
<br />
<button @click=changeLoginType>Change Username</button>
</div>`,
data: () => {
return { loginType: "email" };
},
methods: {
changeLoginType() {
if (this.loginType === "email") this.loginType = "username";
else this.loginType = "email";
}
}
});
Executable CodeSandbox: https://codesandbox.io/s/jovial-elion-cntkin?file=/src/index.js
This code renders a switchable input (switches between "email" input and "username" input). I got this code from Vue.js 2 documentation: https://v2.vuejs.org/v2/guide/conditional.html#Controlling-Reusable-Elements-with-key
The docs say VUe.js is reusing the input element in v-if
block and v-else
block, so the value user entered stays the same. It does not reset when you switch between username and email. But in my code, the first example's input is reset on toggle. Is that because Vue.js only keeps the first-level direct-child identical elements (label
in this case)? I mean it changes every attribute and all HTML
content of it and just not the element itself?
I tried playing with it a little bit and I'm trying to find a way to tell Vue.js to reuse the input in the code excerpt below:
<div v-if="loginType === 'username'">
<label>Username: <input/></label>
</div>
<div v-else>
<label>Email: <input/></label>
</div>
(by reuse I mean if I switch the loginType
I except the value of the input
stays the same as user entered.
CodePudding user response:
In MVVM world the better option is not to rely on framework in sence that it re-uses things like we see it, but to use "VM" and explicitly bind data in component templates. The idea is not to re-use DOM as much as possible (actually, I never rely on that), but "to connect" input values to each other so no matter if they're re-used or not, visually they'll always display same data
What you have to do is to define state property in component and attach it to both inputs using "v-model" directive:
<template>
<div v-if="loginType === 'username'">
<label>Username: </label>
<input v-model="userLogin" />
</div>
<div v-else>
<label>Email: </label>
<input v-model="userLogin" />
</div>
<button @click="changeLoginType()">Change Username</button>
</template>
<script>
export default {
name: 'App',
data: () => {
return { loginType: 'email', userLogin: '' };
},
methods: {
changeLoginType() {
if (this.loginType === 'email') this.loginType = 'username';
else this.loginType = 'email';
},
},
};
</script>
In this scenario no metter which of options you choose, your input value would always take value from component state and changes in input would be reflected in state (so-called 2-way data binding)
Also, interesting thing here is that when I played with initial code sample in newly created application using Vue 3 - input value was always reset when clicking the button and changing login type. So, no matter how it behaves in Vue 2, in newer versions of Vue things could change and previously working code could fail, so it's definitely better to define things explicitly in terms of long-term project support
CodePudding user response:
The key
attribute is key when using v-for
but it also helps with v-if
/v-else
. It prevents Vue from reusing the same DOM node.
You should try something like this:
<template>
<div>
<label for="account">{{ loginType === 'username' ? 'Username' : 'E-mail' }}</label>
<input id="account" v-model.trim="usernameOrEmail" :type="loginType === 'username' ? 'text' : 'email'">
</div>
</template>
CodePudding user response:
As in Vue, You have to pass the inputs value from View to Model or vice versa (two way data binding) and to achieve this you need v-model
directive of Vue.
Now, To achieve the requirement you have to just bind the input value to a variable and then reset/clear it on the changeLoginType()
method.
Live Demo :
new Vue({
el: '#app',
data: {
loginType: "email",
inputVal: ''
},
methods: {
changeLoginType() {
this.inputVal = '';
this.loginType = this.loginType === 'email' ? 'username' : 'email';
}
}
})
<div id="app">
<div v-if="loginType === 'username'">
<label>Username: </label>
<input v-model="inputVal"/>
</div>
<div v-else>
<label>Email: </label>
<input v-model="inputVal"/>
</div>
<button @click=changeLoginType>Change Username</button>
</div>