Sample dropdown ajax with rails
Bài đăng này đã không được cập nhật trong 7 năm
Intro
If you haven't done ajax before. This article is all you need. This sample uses ajax with ruby on rails (server)
Problems
Imagine you have a form which has 2 dropdowns
- Country
- City
A country has many cities and the city must be belongs to a country. Problem here, when you select the country, you want the city must be dynamic follow the country.
Let's do it
Create 2 models country
and city
with the relationship 1-n
This sample builds an user register form 2 fields country and city.
Create a form with 2 dropdowns
On controller:
@user = User.new
@countries = Country.all
@cities = []
On the view
div.col-md-6.col-md-offset-3
= form_tag new_user_path do
#country.form-group
= select_tag :country, options_for_select(@countries.collect{|p| [p.name, p.id]}, selected: params[:country]),
prompt: "Select country", class: "form-control"
#city.form-group
= select_tag "city", options_for_select(@cities.collect{|p| [p.name, p.id]}, selected: params[:city]),
prompt: "Select city", class: "form-control"
That's all for preparing. Let's do ajax now
The theory
AJAX is very simple. STEP 1. Clients send a request to server. STEP 2. Server receives the request, then calculates and sends the results to clients. STEP 3. Client receives the response. And do anything you want (replace the views, show alert...)
Practice step by step
STEP 1: Client sends a request to server.
Sample code
$(document).on("change", "#country select", function(){
var country = $(this).val();
$.ajax({
url: "/users/new",
method: "GET",
dataType: "json",
data: {country: country},
error: function (xhr, status, error) {
console.error('AJAX Error: ' + status + error);
},
success: function (response) {
console.log(response);
}
});
});
Firstly, you catch the event, here's on change
dropdown.
Then do the ajax simply with some infos: url
(target address), method
(action method), data type
(type of data response) and data
(client sent to server)
The success
and error
are the results when ajax completes (success or failure). They are step 3.
STEP 2: Server receives the request, then calculates and sends the results to clients.
Now, the server receives the data sent from clients (when dropdown country changed) and it must be processed with that data.
Here, clients send the country_id
to server, and want to get the city list.
Add the follow code to controller
if params[:country].present?
@cities = Country.find(params[:country]).cities
end
if request.xhr?
respond_to do |format|
format.json {
render json: {cities: @cities}
}
end
end
It just finds the cities corresponding to the country, then sends back to the client.
The full controller
@user = User.new
@countries = Country.all
@cities = []
if params[:country].present?
@cities = Country.find(params[:country]).cities
end
if request.xhr?
respond_to do |format|
format.json {
render json: {cities: @cities}
}
end
end
STEP 3: Client receives the response then builds the dropdown city.
Back to javascript.
Now, if ajax success, you can see the respone by console.log(respone). All you need to do now is build a cities dropdown from the response. Correct your js like bellow:
success: function (response) {
console.log(response);
var cities = response["cities"];
$("#city select").append('<option>Select city</option>');
for(var i=0; i< cities.length; i++){
$("#city select").append('<option value="' + cities[i]["id"] + '">' + cities[i]["name"] + '</option>');
}
}
Great! That works. Is it done? Not yet. Look, your city dropdown. It has 2 items select city. And plz change the country and look at the city. What's that? Don't worry. It seems you are not clear the dropdown after select other country. Very simple, just add bellow code before you build dropdown city
$("#city select").empty();
The complete javascript
$(document).on("change", "#country select", function(){
var country = $(this).val();
$.ajax({
url: "/users/new",
method: "GET",
dataType: "json",
data: {country: country},
error: function (xhr, status, error) {
console.error('AJAX Error: ' + status + error);
},
success: function (response) {
console.log(response);
var cities = response["cities"];
$("#city select").empty();
$("#city select").append('<option>Select city</option>');
for(var i=0; i< cities.length; i++){
$("#city select").append('<option value="' + cities[i]["id"] + '">' + cities[i]["name"] + '</option>');
}
}
});
});
What should I do more? Hmm! May be your ajax works fine now. But in case of server's busy and takes more time to response. User can't know ajax is being processed.
You should let user know that. Very simple, just add an image (*.gif)
when ajax starts, and hide it when ajax is done (error
or success
)
That's your exercise!
That's all
Happy coding!!!!
All rights reserved