Kheran
Kheran

Reputation: 552

Vue watch multiple bindings change within a dropdown update

I require a lookup dropdown where I should be able to watch for multiple data changes. Currently I have this in my html:

<input list="allUsernames" type="text" v-model="selectedUser">
<datalist id="allUsernames">
  <option v-for="(user, index) in allUsers" 
   :id="user.USERID" 
   :value="user.USERNAME" 
   :email="user.EMAIL">
  </option>
</datalist>

My script data tag looks like this:

data(){
  return{
    allUsers: [],
    selectedUserID: '',
    selectedUserEmail: '',
    selectedUser: '',
  }
}

allUsers gets filled by an SQL call containing USERID, USERNAME and EMAIL.

I want a watch to be able to get the :id and the :email part of the option tag, but right now I can only seem to retrieve the value by default:

watch: {
  selectedUser(val, oldval)
  {
    console.log('this only returns the :value binding:' + val);
    //how do I get :id and :email values?
  }
},

I want to set selectedUserID and selectedUserEmail based on the dropdown option selection made, using the vbindings :id and :email (so that I get the user.USERID and user.EMAIL values), how do I do this?

Upvotes: 1

Views: 163

Answers (1)

Dan
Dan

Reputation: 63099

You can do this more cleanly with only the v-model data, and no watch is necessary:

data(){
  return{
    allUsers: [],
    selectedUser: ''
  }
}

Only the value binding is necessary on the options:

<option v-for="(user, index) in allUsers" :value="user.USERNAME"></option>

Use a computed to track the full object of the selected user:

computed: {
  selected() {
    return this.allUsers.find(user => user.USERNAME === this.selectedUser);
  }
}

The selected computed refers to the whole object of the selected user, so you can use selected.USERID and selected.EMAIL in both the instance and the template.

Here's a demo:

new Vue({
  el: "#app",
  data(){
    return{
      allUsers: [
        { USERID: 1, USERNAME: 'name1', EMAIL: 'email1' },
        { USERID: 2, USERNAME: 'name2', EMAIL: 'email2' },
        { USERID: 3, USERNAME: 'name3', EMAIL: 'email3' },
      ],
      selectedUser: ''
    }
  },
  computed: {
    selected() {
        return this.allUsers.find(user => user.USERNAME === this.selectedUser);
    }
  }
});
.display {
  margin-top: 30px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <input list="allUsers" type="text" v-model="selectedUser">
  <datalist id="allUsers">
    <option v-for="(user, index) in allUsers" :value="user.USERNAME"></option>
  </datalist>
  
  <div v-if="selected" class="display">
    <div>ID: {{ selected.USERID }}</div>
    <div>EMAIL: {{ selected.EMAIL }}</div>
  </div>
</div>


A good key to remember is that a watch is only necessary if you want to perform an async or time-based action when data changes. Otherwise, in most cases, use a computed.

Upvotes: 1

Related Questions