How to swap input fields with Vue? - javascript

I am having difficulty to swap fields when a click event is triggered. Here is my code below, which is just changing the value and name once but it does not work if I click again. It also does not change the v-model value. Can anyone help me please?
HTML
<div id='app'>
<button #click="swapInputFields">Swap</button>
<input type="text" :name="[field1]" v-model="model1" :value="[fromCity]"><br>
<input type="text" :name="[field2]" v-model="model2" :value="[toCity]">
</div>
Vue code:
var app = new Vue({
el: '#app',
data: {
fromCity:'FROM',
toCity :'TO',
field1 :'name1',
field2 :'name2'
},
methods: {
swapInputFields()
{
this.fromCity = 'TO';
this.toCity ='FROM';
this.field1 = 'name2';
this.field2 ='name1';
}
}
});

Remove the [ ] brackets from the bindings and remove all of the attributes from the inputs other than type and v-model:
<button #click="swapInputFields">Swap</button>
<input type="text" v-model="fromCity"><br>
<input type="text" v-model="toCity">
You only need those model variables fromCity and toCity in your data:
data() {
return {
fromCity:'FROM',
toCity :'TO'
}
},
And swap them like this:
swapInputFields()
{
const temp = this.fromCity;
this.fromCity = this.toCity;
this.toCity = temp;
}
Here is a demo:
new Vue({
el: "#app",
data(){
return {
fromCity:'FROM',
toCity :'TO'
}
},
methods: {
swapInputFields()
{
const temp = this.fromCity;
this.fromCity = this.toCity;
this.toCity = temp;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="swapInputFields">Swap</button>
<input type="text" v-model="fromCity"><br>
<input type="text" v-model="toCity">
</div>

Related

How to get access to object properties of localStorage object by Vue.js

I have 2 HTML pages and I need to get data on one and display on the second. I tried to use Vue and localStorage, but I cannot get access to Object properties. For example, in tag I want to see name, but there's nothing when I inspect element.
First Page
HTML:
<div>
<input id="name" name="name" type="text" v-model="name" required>
</div>
<div>
<input id="surname" name="surname" type="text" v-model="surname" required>
</div>
<input type="submit" :click="submitForm()" value="Submit">
JS:
const Delivey = {
delimiters: ['${', '}'],
data() {
return {
checked: true,
person: {
name:'',
surname:'',
}
}
},
methods: {
submitForm() {
localStorage.setItem('person',this.person);
}
}
}
const delivery = Vue.createApp(Delivey);
delivery.mount('#go-form');
Second page
HTML:
<div class="info-th" id="info-th">
<p> ${person.name} </p>
</div>
JS:
const Info = {
delimiters: ['${', '}'],
data() {
return {
person: {
name: "",
surname: ""
},
}
},
mounted() {
return this.person = localStorage.getItem('person');
}
}
const info = Vue.createApp(Info);
info.mount('#info-th');

How to Vue let input value v-model with v-bind:value operation

Like below code I hope set input2 v-model bind with data-value2,and the value is operationed from value1 * 2, but it does not work and throw error:
[Vue warn]: Error compiling template:
v-bind:value="value1*2" conflicts with v-model on the same element because the latter already expands to a value binding internally
<div id="app">
<input id="input1" type="number" v-model="value1">
<input id="input2" type="number" v-model="value2" v-bind:value="value1*2">
</div>
<script>
var myObject = new Vue({
el: '#app',
data: {
value1: 1,
value2: 1
}
})
</script>
What I've tried:
I can create a onchange method to do it, but it need to duplicate adding v-on:change="operateValue" code to input.
<div id="app">
<input type="number" v-model="value1" v-on:change="operateValue">
<input type="number" v-model="value2" v-on:change="operateValue">
<input type="number" v-model="value3">
</div>
<script>
var app = new Vue({
el: '#app',
data: {
value1: 1,
value2: 1,
value3 : 1
},
methods:{
operateValue:function(){
app.$data.value3 = (app.$data.value1 * 1 + app.$data.value2 * 1 ) * 2;
}
}
})
</script>
Is it possible? Or I have create a method to custom the operation?
You cannot use v-model and v-bind:value on the same element because it gives you an error.
You can however use a computed property instead:
var myObject = new Vue({
el: '#app',
data: {
value1: 1
},
computed: {
value2: function() {
return this.value1 * 2;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input id="input1" type="number" v-model="value1">
<input id="input2" type="number" v-bind:value="value2">
</div>
You can then also access 'value2' by using:
console.log(myObject.value2);
For more infos refer to https://v2.vuejs.org/v2/guide/computed.html
You cannot do that since v-model is just shorthand for :value="someVar" and#update="setSomeVar"` what you can do is split them then you should have no problem.
So just write something like above:
<input id="input1" type="number" v-model="value1" #input="value2 = $event*2">
<input id="input2" type="number" :value="value2">

Click-and-edit text input with Vue

I'm looking for a click-and-edit Vue component.
I've found a fiddle and made some edits. It works like this:
The fiddle is here.
The problem: I need an additional click to make the input focused. How can I make it focused automatically?
The code from the fiddle. HTML:
<div id="app">
Click the values to edit!
<ul class="todo-list">
<li v-for = "todo in todos">
<input v-if = "todo.edit" v-model = "todo.title"
#blur= "todo.edit = false; $emit('update')"
#keyup.enter = "todo.edit=false; $emit('update')">
<div v-else>
<label #click = "todo.edit = true;"> {{todo.title}} </label>
</div>
</li>
</ul>
</div>
JS:
new Vue({
el: '#app',
data: {
todos: [{'title':'one value','edit':false},
{'title':'one value','edit':false},
{'title':'otro titulo','edit':false}],
editedTodo: null,
message: 'Hello Vue.js!'
},
methods: {
editTodo: function(todo) {
this.editedTodo = todo;
},
}
})
You can use a directive, for example
JS
new Vue({
el: '#app',
data: {
todos: [
{ title: 'one value', edit: false },
{ title: 'one value', edit: false },
{ title: 'otro titulo', edit: false }
],
editedTodo: null,
message: 'Hello Vue.js!'
},
methods: {
editTodo: function (todo) {
this.editedTodo = todo
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
})
HTML
<div id="app">
Click the values to edit!
<ul class="todo-list">
<li v-for="todo in todos">
<input
v-if="todo.edit"
v-model="todo.title"
#blur="todo.edit = false; $emit('update')"
#keyup.enter="todo.edit=false; $emit('update')"
v-focus
>
<div v-else>
<label #click="todo.edit = true;"> {{todo.title}} </label>
</div>
</li>
</ul>
</div>
You can find more info here
https://v2.vuejs.org/v2/guide/custom-directive.html
With #AitorDB's help I have written a Vue component for this, I call it Click-to-Edit. It is ready to use, so I'm posting it.
What it does:
Supports v-model
Saves changes on clicking elsewhere and on pressing Enter
ClickToEdit.vue: (vue 2.x)
<template>
<div>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
#keyup.enter.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
v-focus=""
/>
<p v-else="" #click="edit = true;">
{{valueLocal}}
</p>
</div>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>
Edit for 3.x: [Breaking changes between 2.x and 3.x]
remove .native from the event handlers
change the focus hook to mounted as described in Custom Directives 3.x.
Built on #Masen Furer's work. I added some protection to handle when a user deletes all of the data. There is probably a way to accomplish this using "update" but I couldn't get it working.
I also added the ability to hit escape and abandon any changes.
<template>
<span>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur="save($event);"
#keyup.enter="save($event);"
#keyup.esc="esc($event);"
v-focus=""/>
<span v-else #click="edit = true;">
{{valueLocal}}
</span>
</span>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value,
oldValue: (' ' + this.value).slice(1)
}
},
methods: {
save(event){
if(event.target.value){
this.valueLocal = event.target.value;
this.edit = false;
this.$emit('input', this.valueLocal);
}
},
esc(event){
this.valueLocal = this.oldValue;
event.target.value = this.oldValue;
this.edit = false;
this.$emit('input', this.valueLocal);
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>

How to point out this to a certain element in VueJS?

I am creating a form. When a input is focused, then the color of label should be blue. But it looks like something is wrong in my code. I am unable to point out this to the input.
Here's the code which doesn't work:
new Vue({
el: '#app',
data: {
inputs: document.querySelector('.input')
},
methods: {
changeColor(){
this.inputs.previousElementSibling.style.color = "blue";
}
}
});
<div id="app">
<label for="input">Input</label>
<input type="text" class = "input" v-on:focus = "changeColor"><br /><br />
</div>
<script type = "text/javascript" src = "https://vuejs.org/js/vue.js"></script>
Here's the code that works:
new Vue({
el: '#app',
data: {
inputs: document.querySelector('.input')
},
methods: {
changeColor(){
document.querySelector('.input').previousElementSibling.style.color = "blue";
}
}
});
<div id="app">
<label for="input">Input</label>
<input type="text" class = "input" v-on:focus = "changeColor"><br /><br />
</div>
<script type = "text/javascript" src = "https://vuejs.org/js/vue.js"></script>
So, my question why this.inputs doesn't work but document.querySelector('.input') works?
I have a simpler alternative that gives more flexibility
new Vue({
el: '#app',
props: ['styles'],
methods: {
changeStyles() {
this.styles = {
color: 'blue' // Add more CSS rules if you want
}
},
restoreStyles() {
this.styles = {
color: 'black'
}
}
}
})
<div id="app">
<label :style="styles">Input</label>
<input type="text" #focus="changeStyles" #focusout="restoreStyles">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
Hope it helps. And the for attribute in label tag only works with id of the bound input field.
Check the console output of this snippet:
new Vue({
el: '#app',
data: {
inputs: document.querySelector('.input')
},
methods: {
changeColor(){
console.log('Are the similar? answer: ',
this.inputs == document.querySelector('.input'));
this.inputs.previousElementSibling.style.color = "blue";
}
}
});
<div id="app">
<label for="input">Input</label>
<input type="text" class = "input" v-on:focus = "changeColor"><br /><br />
</div>
<script type = "text/javascript" src = "https://vuejs.org/js/vue.js"></script>
After Vue instance is created it replaces all elements inside the #app in its own flavor. Your inputs field is set at the moment of creating Vue instance and before mounting the #app component. So the thing that you store in the this.inputs is long dead!
You should probably read through the Reactivity in Depth very carefully. And as suggested by the #Shreevardhan's answer, you should always use Vue's way to manipulate Vue's stuffs.

Vue2: Avoid mutating a prop directly inside component

I'm gettig this "Avoid mutating a prop directly", when checking if the persons input should get an invalid class because its empty.
<script type="text/x-template" id="srx">
<input type="number" name="persons" id="persons" value="" v-model="persons" :class="{invalid: !persons}">
</script>
<div id="app">
{{stepText}}
<sr-el :persons="1"></sr-el>
<button v-if="currentStep > 1" type="button" v-on:click="previous()">prev</button>
<button v-if="currentStep < 6" type="button" :disabled="currentStepIsValid()" v-on:click="next()">
next</button>
</div>
Vue.component('sr-el', {
template: '#srx',
props: ['persons'],
})
var App = window.App = new Vue({
el: '#app',
data: {
persons: '1'
currentStep: 1,
},
methods: {
currentStepIsValid: function() {
if (this.currentStep == 1) {
this.stepText = "Step 1;
return !(this.persons > 0);
}
},
previous: function() {
this.currentStep = this.currentStep - 1;
// prev slide
},
next: function() {
this.currentStep = this.currentStep + 1;
// next slide
}
}
})
You're getting that warning because you are binding persons to the input in the template via v-model. Changing the input's value will thus change the value of persons, which means the prop is getting mutated directly in your sr-el component.
You should set a new property equal to persons and pass that to v-model instead:
Vue.component('sr-el', {
template: '#srx',
props: ['persons'],
data: function() {
return {
inputVal: this.persons,
}
}
})
<input v-model="inputVal" ... />

Categories