I’m using Vue.js to load an HTML datalist. Whenever I type in my input box that is connected to my datalist, my page freezes (using Chrome). I’m using jQuery to make an AJAX call to initially get all of my users when the page loads, then using the JavaScript filter function to make a new array that has indexOf
whatever is typed in my input box, then putting that new filtered array of objects into the datalist element.
Here is my HTML:
<div id="my-app"> <input list="user-search" type="text" id="find-user" name="find-user" v-model="findUser"> <datalist id="user-search"> <option v-for="user in findUserList">{{ user.vendorName }}</option> </datalist> </div>
Here is my Vue JavaScript:
var myApp = new Vue({ el: '#my-app', data: { users: [], findUser: '', findUserList: '', }, watch: { findUser: function(val) { this.findUserResults(); } }, methods: { findUserResults: function() { var lookFor = this.findUser.toLowerCase(); this.findUserList = this.users.filter(function(user) { return (user.vendorName.toLowerCase().indexOf(myApp.findUser.toLowerCase()) > -1 || user.email.toLowerCase().indexOf(myApp.findUser.toLowerCase()) > -1); }); }, loadUsers: function() { $.ajax({ method: 'GET', url: '/users', success: function(data) { myApp.users = JSON.parse(data); }, error: function() { console.log('error...'); } }); } }, mounted: function() { this.loadUsers(); } })
The users load fine when the page loads. No problems there. I even commented out the v-for
and just console.log
‘d the results of the filter with no problem either. The issue comes in when I implement dynamically adding the <option>
values in the <datalist>
. I’ve tried wrapping the options in the vue <template>
tag and moving the v-for
there with no success.
I have this working fine on another page, but instead I’m populating a table with <tr>
and <td>
instead of <datalist>
and <option>
.
What could be causing my page to crash? Is <datalist>
not good enough to handle all of this? Maybe I’m missing something that a second set of eyes could help solve.
EDIT
The data that is being populated into users
looks like this (it’s an array of objects):
[{id:1, vendorName:'john'}, {id:2, vendorName:'Rachel', {id:3, vendorName:'Steve'}]
ANSWER
This was actually just an example of someone overthinking (me). B.Fleming’s answer about this being recursive clued me into why my approach above was incorrect. There is no need to keep reloading the datalist options every time the user types. That’s exactly what <datalist>
being linked to <input>
does; no JavaScript needed. All I need(ed) to do was load all ~3,000 of my users into the <datalist>
tag as <option>
s on page load (or whenever I want the input and datalist to show up), and let the datalist and input handle the rest. I haven’t tested this with the app in the example above because I’m not near that computer, but just as a proof of concept that a datalist can handle thousands of option elements, I wrote this and ran it locally with no issue (not sure why the snippet console keeps saying there is an error when it works):
window.onload = function() { var datalistElement = document.getElementById('datalist-test'); var datalistString = ''; for (var i = 0; i < 3000; i++) { datalistString += '<option>' + Math.random().toString(36).substring(7); + '</option>'; } datalistElement.innerHTML = datalistString; }
<!DOCTYPE html> <html> <head> <title>Datalist Test</title> </head> <body> <input list="datalist-test" type="text"> <datalist id="datalist-test"> </datalist> </body> </html>
3,000 datalist option elements, and it’s fine.
Advertisement
Answer
You have infinitely recursive calls. You’re calling myApp.findUser()
on entering/deleting search text, which calls myApp.findUserResults()
, which calls myApp.findUser()
, etc. You’ll need to fix this.
To fix this, all you have to do is load all of the users into the datalist options once. Then, let the input box and datalist handle the rest. No need to keep reloading the datalist options every time the user types.