VueJS , LoDash debounce watch on entire form - javascript

I'm trying to get LoDash debounce to work to trigger an event when a user stops typing on a form.
Something similar to this guide
Except I want to apply it to the entire form/model properties.
At the moment the debounce never fires.
Example JS Fiddle
JS
new Vue({
el: "#app",
data() {
return {
form: {
user: {
name: "Bob",
email: "Test#test.com"
}
},
isTyping: false,
isLoading: false,
}
},
watch: {
form: _.debounce(function() {
this.isTyping = false;
}, 1000),
isTyping: function(value) {
if (!value) {
console.log("stopped typing")
}
}
},
methods: {
}
})
HTML
<div id="app" class="container-fluid">
<div class="row">
<div class="col-md-3">
<label class="control-label">Name</label>
<input type="text" class="form-control" #input="isTyping = true" v-model="form.user.name" placeholder="Type your keyword">
<label class="control-label">Email</label>
<input type="text" class="form-control" #input="isTyping = true" v-model="form.user.email" placeholder="Type your Email">
</div>
</div>
</div>

You need to make your watcher deep
form: {
handler: _.debounce(function() {
this.isTyping = false;
}, 1000),
deep: true
},
Updated fiddle

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');

why the el-input could not input anything in google chrome extension

Now I am writing a Google Chrome Extension that using vue el-input to input the username and password, when input username and password, store the username and password into storage.the code like this:
<template>
<div class="login">
<div class="title">Login</div>
<div class="setting-name">username:</div>
<div class="setting-input">
<el-input #change="saveConfig" placeholder="please input username" ></el-input>
</div>
<div class="setting-name">password:</div>
<div class="setting-input">
<el-input #change="saveConfig" placeholder="please input password"></el-input>
</div>
</div>
</template>
but when I type the username and password in the UI, the el-input did not show what I am inputting. It means could not input anything. what should I do to fix it? The vue version is:
"vue": "2.6.12",
"vue-loader": "15.9.5",
"vue-template-compiler": "2.6.12",
I have tried to forceUpdate like this:
<el-input #change="saveConfig" placeholder="please input username" #input="onInput()"></el-input>
methods: {
onInput(){
this.$forceUpdate();
},
}
still not work. This is my full code:
<template>
<div class="login">
<div class="title">登录</div>
<div class="setting-name">用户名:</div>
<div class="setting-input">
<el-input #change="saveConfig" placeholder="请输入你的用户名" #input="onInput()"></el-input>
</div>
<div class="setting-name">密码:</div>
<div class="setting-input">
<el-input #change="saveConfig" placeholder="请输入你的密码"></el-input>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
data: () => ({
loading: true,
defaultConfig,
config: defaultConfig,
time: '',
leftTime: '',
second: 0,
refreshDisabled: false,
isChrome: navigator.userAgent.indexOf('Chrome') !== -1,
}),
methods: {
onInput(){
this.$forceUpdate();
},
saveConfig() {
saveConfig(this.config, () => {
this.$message({
message: '保存成功',
type: 'success'
});
});
},
toHotkey() {
chrome.tabs.create({
url: 'chrome://extensions/shortcuts'
});
},
refreshRu() {
this.refreshDisabled = true;
refreshRules(() => {
this.second = 0;
this.time = secondToTime(this.second);
this.leftTime = secondToTime(this.config.refreshTimeout - this.second);
this.refreshDisabled = false;
});
},
refreshTime() {
getRulesDate((date) => {
this.second = (+new Date - +date) / 1000;
this.time = secondToTime(this.second);
this.leftTime = secondToTime(this.config.refreshTimeout - this.second);
setTimeout(() => {
this.refreshTime();
}, 1000);
});
}
}
}
</script>

How to swap input fields with Vue?

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>

Populate input fields with data from vuex state in vue

I have the following code snippet from my app component:
<template>
<div>
<h3>Basic</h3>
<div v-for="(field, index) in basics" :key="index">
<input v-model="basics.name" placeholder="Name" type="text">
<br>
<br>
<input v-model="basics.email" placeholder="Email" type="email">
<br>
<hr/>
<button #click.prevent="addField">Add</button>
<button #click.prevent="removeField(index)">Remove</button>
<br>
<button #click.prevent="back">Back</button>
<button #click.prevent="toNext">Next</button>
</div>
</div>
</template>
<script>
import { mapActions } from "vuex";
export default {
name: "Basics",
data() {
return {
basics: [{
name: "",
email: ""
}]
};
},
methods: {
...mapActions(["addBasicData"]),
addFied(){
this.basics.push({
name: "",
email: ""
});
},
removeField(index){
this.basics.splice(index, 1);
},
toNext() {
this.addBasicData(this.basics);
this.$router.push({ name: "Location" });
},
back() {
this.$router.back();
}
}
};
</script>
In the code above when I finish filling up the form and click next button the data is sent to the state and we are guided to another route named "Location".
When I click back button in the "Location" route I'm back to route named "Basic".
The issue here is when I'm brought back to the route named "Basic" the form fields are empty although they are binded with the data object.
How do I populate these input fields when I return back to same route ?
Here is the working replica of the app: codesandbox
<div v-for="(field, index) in basics" :key="index">
<input v-model="basic.name" placeholder="Name" type="text">
<input v-model="basic.email" placeholder="Email" type="email">
<button #click.prevent="removeField(index)">Remove</button>
</div>
<hr/>
<button #click.prevent="addField">Add</button>
<br>
<button #click.prevent="back">Back</button>
<button #click.prevent="toNext">Next</button>
methods: {
addField() {
this.$store.commit('addBasic',{name:"",email:""} )
},
removeField(index) {
this.$store.commit('removeField',index )
},
toNext() {
this.$router.push({ name: "Location" });
}
},
computed: {
basic:{
get() {
return this.$store.getters.getBasic;
}
}
}
store.js
// ...
state: {
basic:[{name:"Jonny",email:"jonny#mail.com"},
{name:"Bonny",email:"Bonny#mail.com"}]
}
mutations: {
addBasic(state,value) {
state.basic.push(value)
},
removeField(state,index ){
state.basic.splice(index,1);
}
}
Thats just one of two versions how you can do it.
Or you can map the mutatations and call them directly in the click event.
https://vuex.vuejs.org/guide/mutations.html
https://vuex.vuejs.org/guide/forms.html
The add field button makes only sense outside of the loop.
addBasicData you dont need it
This method somehow works:
mounted() {
// eslint-disable-next-line no-unused-vars
let fromState = this.$store.state.Basics.basics;
if (fromState) {
this.basics.name = fromState.name;
this.basics.email = fromState.email;
}
}
I will really appreciate if there are any other convenient method to achieve this.
Tried mapState but didn't work

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>

Categories