Skip to content

Instantly share code, notes, and snippets.

@tabishiqbal
Last active October 16, 2024 20:39
Show Gist options
  • Save tabishiqbal/dc78239aa5b81b257db0633ace75ecc0 to your computer and use it in GitHub Desktop.
Save tabishiqbal/dc78239aa5b81b257db0633ace75ecc0 to your computer and use it in GitHub Desktop.
Ruby on Rails Tom-Select Example with Stimulus controller
<%= form_with(model: team) do |form| %>
<div>
<%= form.label :name %>
<%= form.text_field :name, class: "input" %>
</div>
<div>
<%= f.select :user_id, {}, {placeholder: "Select user"}, {class: "w-full", data: { controller: "select", select_url_value: users_path }} %>
</div>
<%= form.submit "Save product", class: "btn-primary" %>
<% end %>
// app/javascript/controllers/select_controller.js
import { Controller } from "stimulus";
import TomSelect from "tom-select";
export default class extends Controller {
// Define static value to fetch the URL from HTML data attributes.
static values = { url: String };
// Triggered when the Stimulus controller is connected to the DOM.
connect() {
this.initializeTomSelect();
}
// Triggered when the Stimulus controller is removed from the DOM.
disconnect() {
this.destroyTomSelect();
}
// Initialize the TomSelect dropdown with the desired configurations.
initializeTomSelect() {
// Return early if no element is associated with the controller.
if (!this.element) return;
// Construct URL for fetching data which comes from the static value.
// https://tom-select.js.org/examples/remote/
const url = `${this.urlValue}.json`;
// Fetch data for the dropdown.
const fetchData = (search, callback) => {
fetch(url)
.then(response => response.json()) // Convert response to JSON.
.then(data => callback(data)) // Send data to TomSelect.
.catch(() => callback()); // Handle any errors.
};
// Define custom rendering for dropdown options.
// see: https://tom-select.js.org/examples/customization/
const renderOption = (data, escape) => {
return `
<div>
<span class="block">${escape(data.name)}</span>
<span class="text-gray-400">${escape(data.email)}</span>
</div>
`;
};
// Create a new TomSelect instance with the specified configuration.
// see: https://tom-select.js.org/docs/
// value, label, search, placeholder, etc can all be passed as static values instead of hard-coded.
this.select = new TomSelect(this.element, {
plugins: ['remove_button'],
valueField: 'id',
labelField: 'name',
searchField: ['name', 'email'],
maxItems: 1,
selectOnTab: true,
placeholder: "Select user",
closeAfterSelect: true,
hidePlaceholder: false,
preload: true,
create: false,
openOnFocus: true,
highlight: true,
sortField: { field: "name", direction: "asc" },
load: fetchData,
render: {
option: renderOption
}
});
}
// Cleanup: Destroy the TomSelect instance when the controller is disconnected.
destroyTomSelect() {
if (this.select) {
this.select.destroy();
}
}
}
class UsersController < ApplicationController
def index
# ... (other code)
respond_to do |format|
# ... (other formats)
format.json { render json: format_users_as_json(@users) }
end
end
private
def format_users_as_json(users)
users.map do |user|
{
name: user.name,
id: user.id,
email: user.email
}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment