Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.JS value tied on input having the focus

Tags:

vue.js

onfocus

Is there a way to change a value in the model when an input gets/loses focus?

The use case here is a search input that shows results as you type, these should only show when the focus is on the search box.

Here's what I have so far:

<input type="search" v-model="query"> <div class="results-as-you-type" v-if="magic_flag"> ... </div> 

And then,

new Vue({   el: '#search_wrapper',   data: {     query: '',     magic_flag: false   } }); 

The idea here is that magic_flag should turn to true when the search box has focus. I could do this manually (using jQuery, for example), but I want a pure Vue.JS solution.

like image 780
cambraca Avatar asked Jan 11 '17 21:01

cambraca


People also ask

Is Vue 2 way data binding?

Vue is also perfectly capable of powering sophisticated Single-Page Applications in combination with modern tooling and supporting libraries. The v-model directive makes two-way binding between a form input and app state very easy to implement.

How do I get input value from Vue?

The v-model directive in Vue creates a two-way binding on the input element. All you need to do is simply declare a v-model directive for the input element and reference it to get the value. Every time the input value changes, “myInput” model will keep track of the changes.

How do you set a global variable in Vue?

In case of "global" variables—that are attached to the global object, which is the window object in web browsers—the most reliable way to declare the variable is to set it on the global object explicitly: window. hostname = 'foo';

What is V-model lazy in Vue?

.lazy. By default, v-model syncs the input with the data after each input event (with the exception of IME composition as stated above). You can add the lazy modifier to instead sync after change events: template <!--


2 Answers

Apparently, this is as simple as doing a bit of code on event handlers.

<input    type="search"    v-model="query"   @focus="magic_flag = true"   @blur="magic_flag = false" /> <div class="results-as-you-type" v-if="magic_flag"> ... </div> 
like image 66
cambraca Avatar answered Oct 02 '22 05:10

cambraca


Another way to handle something like this in a more complex scenario might be to allow the form to track which field is currently active, and then use a watcher.

I will show a quick sample:

<input     v-model="user.foo"     type="text"     name="foo"     @focus="currentlyActiveField = 'foo'" >  <input     ref="bar"     v-model="user.bar"     type="text"     name="bar"     @focus="currentlyActiveField = 'bar'" > 

...

data() {     return {         currentlyActiveField: '',         user: {             foo: '',             bar: '',         },     }; },  watch: {     user: {         deep: true,         handler(user) {             if ((this.currentlyActiveField === 'foo') && (user.foo.length === 4)) {                 // the field is focused and some condition is met                 this.$refs.bar.focus();             }         },     }, }, 

In my sample here, if the currently-active field is foo and the value is 4 characters long, then the next field bar will automatically be focused. This type of logic is useful when dealing with forms that have things like credit card number, credit card expiry, and credit card security code inputs. The UX can be improved in this way.

I hope this could stimulate your creativity. Watchers are handy because they allow you to listen for changes to your data model and act according to your custom needs at the time the watcher is triggered.

In my example, you can see that each input is named, and the component knows which input is currently focused because it is tracking the currentlyActiveField.

The watcher I have shown is a bit more complex in that it is a "deep" watcher, which means it is capable of watching Objects and Arrays. Without deep: true, the watcher would only be triggered if user was reassigned, but we don't want that. We are watching the keys foo and bar on user.

Behind the scenes, deep: true is adding observers to all keys on this.user. Without deep enabled, Vue reasonably does not incur the cost of maintaining every key reactively.

A simple watcher would be like this:

watch: {     user() {         console.log('this.user changed');     }, }, 

Note: If you discover that where I have handler(user) {, you could have handler(oldValue, newValue) { but you notice that both show the same value, it's because both are a reference to the same user object. Read more here: https://github.com/vuejs/vue/issues/2164

Edit: to avoid deep watching, it's been a while, but I think you can actually watch a key like this:

watch: {     'user.foo'() {         console.log('user foo changed');     }, }, 

But if that doesn't work, you can also definitely make a computed prop and then watch that:

computed: {     userFoo() {         return this.user.foo;     }, },  watch: {     userFoo() {         console.log('user foo changed');     }, }, 

I added those extra two examples so we could quickly note that deep watching will consume more resources because it triggers more often. I personally avoid deep watching in favour of more precise watching, whenever reasonable.

However, in this example with the user object, if all keys correspond to inputs, then it is reasonable to deep watch. That is to say it might be.

like image 45
agm1984 Avatar answered Oct 02 '22 05:10

agm1984