Sử dụng select2 với Rails Controller, AJAX
Bài đăng này đã không được cập nhật trong 6 năm
Chào các bạn, hôm nay chúng ta cùng tìm hiểu về select2 nhé. Nội dung của bài viết này bao gồm các phần như sau:
- Giới Thiệu: Tổng quan về select2, khi nào thì cần sử dụng select2
- Cách cài đặt
- Cách sử dụng select2 bình thường.
- Cách sử dụng select2 với AJAX và dữ liệu load ra màn hình là 1000 records trở lên.
Chúng ta cùng bắt đầu nhé.
Giới thiệu
select2
là một plugin JQuery sử dụng để thay thế select box bình thường, nó có ưu điểm gì mà lại sử dụng nhỉ?
- Giúp bạn
vừa typing vừa search dữ liệu
ngay trên select box, điều mà select box thông thường không làm được. - Hỗ trợ sẵn các option để
custom lại chính select2
cho phù hợp với yêu cầu của từng dự án.
Muốn mường tượng được select2 khi chạy như thế nào thì vào link này xem nhé: https://select2.org/getting-started/basic-usage
Cách cài đặt
Thường sẽ có 2 cách cài đặt là thông qua CDN
hoặc download source
về bỏ vào trong thư mục javascripts. Tất nhiên cách lựa chọn tuỳ thuộc bạn muốn gì, tuy nhiên nên download source về nhé các bạn. Vào link sau download về và bỏ vào thư mục javascripts nhé:
https://github.com/select2/select2/blob/develop/dist/js/select2.full.min.js
VD: nếu bạn bỏ cái select2.full.min.js
trên vào thư mục app/assets/javascripts/libs/
thì ở thư mục application.js
phải require nó vào nhé. Dùng //= require ./libs/select2.full.min.js
là được.
Cách sử dụng select2 thông thường
Giả sử ta có trang Edit User, trên trang này có select2 để chọn cho những user đó các địa điểm làm việc (WorkingLocation
). Thì:
Trong Controller ta sẽ có:
def edit
@user = User.find_by id: params[:id]
@working_locations = WorkingLocation.pluck(:name, :id)
end
Lúc này trong view vẫn dùng f.select như bình thường (select2 sẽ được raise trong file js
):
<div>
<%= f.select :working_location_id, options_for_select(@working_locations, selected: f.object.working_location_id), {include_blank: false}, {id: "working-location-select"} %>
</div>
Ngang đây thì bạn đã có 1 select box bình thường như trước đến giờ, nếu muốn biến nó thành select2
thì: Trong file JS thêm:
$('#working-location-select').select2();
Thế là xong, đã biến select box thông thường thành select2, giờ bạn có thể vừa typing vừa search tên WorkingLocation
rồi đấy.
Cách sử dụng select2 với AJAX và load dữ liệu 1000 records
Trong cách sử dụng trên, để ý rằng khi ta @working_locations
ra thì ta phải load tất cả. Giả sử record bạn chưa nhiều thì không sao, chứ data tầm 1000 records trở lên thì khi vào trang hoặc F5 lại trang sẽ rất lâu
vì ta phải load tất cả 1000 records ra đổ lên select2
mà.
Nên việc giải pháp ở đây là gì? Chính là:
- Ban đầu khi hiển thị ta chỉ load ra
limit 20 records
thôi. - Nhưng khi User bắt đầu nhập search thì ta sẽ
không search trong 20 records này
mà sẽ gọi đến controller vàsearch trong 1000 records trên
. - Sau khi search xong sẽ gửi về lại cho select2 để hiện thị data vừa search được và
vẫn limit 20 records
Tóm lại: Vẫn cung cấp chức năng search của select2 trên toàn bộ dữ liệu, nhưng limit record hiển thị ra màn hình
Trong file JS lúc này, ta sửa lại select2 để nó hoạt động với AJAX, chi tiết có thể tìm hiểu trong link sau: https://select2.org/data-sources/ajax
$('#working-location-select').select2({
width: '100%',
ajax: {
url: '/users/find_working_location',
dataType: 'json',
data: function(params) {
var selectedLocationId = $(this).val();
return { search_content: params.term, selected_location_id: selectedLocationId }
},
processResults: function(data) {
return { results: data.results };
}
},
templateResult: formatResult,
templateSelection: formatSelection,
}).trigger('change');
function formatResult(station) {
return station.name;
}
function formatSelection(station) {
return station.text || station.name;
}
Cùng tìm hiểu sơ qua các options trên của select2
là cái gì nhé.
width
: Là một options cho phép độ rộng của select2 tràn đầy div, nếu thấy select-box không full div thì truyền vào cho nó full div cho đẹp nhé.ajax
: Là options cho phép custom lại select2 và gửi request đến server thông qua các tham số bên trong nó.url
: URL của server chúng ta, trong trường hợp bài viết này là gửi lên server. Vào actionfind_working_location
để lấy dữ liệu theo ý mình.data
: Là function cho phép gửi params kèm theo khi request lên server thông qua optionurl
. Ở đây chúng ta gửiselectedLocationId
cho trường hợp đối với trang Edit User, user sẽ có sẵnworking_location_id
rồi, chúng ta không gửi kèmworking_location_id
lên để search là sai spec nhé các bạn.processResults
: Là dữ liệuselect2
sẽ nhận từ server gửi về và hiển thị lên màn hình (Lưu ý từresults
nhé, bên server phải gửi về format json với cấu trúc {results: []} y chang thì select2 mới nhận.templateResult
: Quy định dữ liệu hiển thị lên select box.templateSelection
: Quy định khi select thì sẽ lấy dữ liệu gì trong phầnresults
được gửi về.
Giờ thì ta qua controller để định nghĩa thêm action find_working_location
nhé:
def edit
@user = User.find_by id: params[:id]
@working_locations = WorkingLocation.limit(20).pluck(:name, :id)
end
def find_working_location
if search_content = params[:search_content].presence # Vì bên select2 gửi qua params search_content nên kiểm tra nếu có thì ta search
# Ta sẽ search trong tất cả records xem có record nào nội dung "like" nội dung đã search không, nếu có lấy limit 20 thôi nhé.
working_locations = WorkingLocation.where("name like ?", "%#{search_content}%").limit(20)
elsif selected_working_location_id = params[:selected_location_id].presence # Trong trường hợp trang edit User đã nhắc ở trên
# Lấy ra working_location đã được chọn từ trước và thêm nó vào 20 record được lấy ra ngẫu nhiên.
selected_working_location = WorkingLocation.find_by id: selected_working_location_id
results = WorkingLocation.where.not(id: selected_working_location.id).take(19).unshift selected_working_location
else # Trường hợp không search, không select từ trước, load ra 20 records đầu tiên
results = WorkingLocation.limit 20
end
render json: {results: results.as_json(only: [:name, :id])}
end
Rồi thế là xong rồi đấy, chúng ta đã cùng nhau tìm hiểu cách sử dụng select2 với AJAX và còn bonus thêm giải pháp cho 1000 records trên select2
nữa.
Xin lưu ý là code trên mình viết thẳng ra luôn, không có tách hàm ra cho đẹp với mục đích dễ theo dõi, nên các bạn nếu áp dụng thì refactor lại cho đẹp nhé. Cảm ơn các bạn rất nhiều, hẹn gặp lại ở bài viết tiếp theo.
All rights reserved