Reputation: 36
Question forum on slim-select: https://github.com/brianvoe/slim-select/discussions/541
Hi, I'm using Ruby on Rails with Stimulus JS and have been using slim select for the past 6 months in my project. My team has got the task of updating performance this quarter. So as a part we are moving the searching part through ajax via slimselect and it is working. The only thing I'm looking at this point is to have a debounce search functionality so we are not hitting the server on every key press. It would be great if somebody can help me achieving this.
import { Controller } from "@hotwired/stimulus"
import SlimSelect from 'slim-select'
import debounce from "debounce";
import { authToken } from '../global'
export default class extends Controller {
connect() {
this.initializeInstance();
}
disconnect() {
this.slimSelect.destroy();
}
initializeInstance() {
this.searchIt = this.searchIt.bind(this);
const options = {
select: this.element,
settings: {
hideSelectedOption: true,
placeholderText: this.placeholder,
allowDeselect: true,
maxValuesShown: 100,
}
}
if (this.optionsUrl) {
options.settings.searchingText = 'Searching...'
options.events = {
search: this.searchIt,
afterOpen: () => {
this.slimSelect.search('');
}
}
}
this.slimSelect = new SlimSelect(options)
// Auto-populate the select with data from the prepopulateUrl
// This comes in handy for applying filters to the select
if (this.prepopulateUrl) {
fetch(this.prepopulateUrl, {
method: 'GET',
headers: {
'Accept': 'application/json',
'X-CSRF-Token': authToken(),
},
})
.then(response => response.json())
.then(data => {
const fieldMappings = this.fieldMappings;
const options = data.map(item => ({ text: item[fieldMappings.text], value: item[fieldMappings.value] }));
const selectedValues = data.map(item => item[fieldMappings.value]);
this.slimSelect.setData(options);
this.slimSelect.setSelected(selectedValues);
})
.catch(error => {
console.error('Error:', error);
});
}
}
reinitializeInstance() {
this.disconnect();
this.initializeInstance();
}
get optionsUrl () {
return this.element.dataset.optionsUrl
}
get placeholder () {
return this.element.getAttribute('placeholder')
}
get fieldMappings() {
return JSON.parse(this.element.dataset.fieldsMapping)
}
get prepopulateUrl() {
return this.element.dataset.prepopulateUrl
}
searchIt (search, currentData) {
return new Promise((resolve, reject) => {
const url = this.optionsUrl.replace('${search}', search);
fetch(url, {
method: 'GET',
headers: {
'Accept': 'application/json',
'X-CSRF-Token': authToken(),
},
})
.then((response) => response.json())
.then(data => {
const fieldMappings = this.fieldMappings;
// Take the data and create an array of options
// excluding any that are already selected in currentData
const options = data.filter((obj) => {
return !currentData.some((optionData) => {
return optionData.value === obj[fieldMappings.value]
})
})
.map((item) => {
return {
text: item[fieldMappings.text],
value: item[fieldMappings.value],
}
})
resolve([...options, ...currentData]);
})
});
}
}
I've tried something like this to achieve and it works when I type something in the search except for the first time when I open the search.
if (this.optionsUrl) {
options.settings.searchingText = 'Searching...'
options.events = {
search: debounce(this.searchIt, 300),
afterOpen: () => {
this.slimSelect.search('');
}
}
}
On opening the search for the first time it gives me:
Have also tried debounce(this.slimSelect.search(''), 300) in the afterOpen but still the same issue
Upvotes: 0
Views: 284
Reputation: 41
Here is a debounce function I use in all of my ROR search forms:
import { Controller } from "@hotwired/stimulus";
import debounce from "debounce";
export default class extends Controller {
initialize() {
this.submit = debounce(this.submit.bind(this), 300);
}
submit() {
this.element.requestSubmit();
}
}
After that in your html you need to do:
<%= form_with url: '/events', method: :get, data: { turbo_frame: "events", turbo_action: "advance", controller: "form", action: "input->form#submit" } do %>
...
<% end %>
<%= turbo_frame_tag "events" do %>
<section>
<%= render @events %>
</section>
<% end %>
Upvotes: 0