Here is quick overview how I made dynamically creating and populating select fields, instead of using one select to display all levels. I am using it for selecting one category when creating a new user. gem awesome_nested_set
View code (new user)
<div id="user_category_select">
<span id="loading" style="display:none;">Loading...</span>
<%= f.select :user_category_id, category_children(@categories), { :include_blank => true } %>
</div>
Helper
def category_children(objects)
if(objects)
output = Array.new
objects.each do |o|
output << [o.name, o.id]
end
output
end
end
controller
def new
@categories = UserCategory.roots
end
def get_nested_categories
if(params[:id])
@categories = UserCategory.find(params[:id]).children
if(!@categories.empty?)
respond_to do |format|
format.js
end
else
render :nothing => true
end
else
render :nothing => true
end
end
Javascript
// get actual values from first select
var real_id = $('#user_category_select select').attr("id");
var real_name = $('#user_category_select select').attr("name");
$('#user_category_select select').live('change', function(){
remove_select_after($(this).next("select"));
if($(this).val()) {
manage_select_class($("#user_category_select select"), $(this), real_id, real_name);
$("#user_category_select #loading").show();
$.get("get_nested_categories",
{ id: $(this).val() }, function() { $("#user_category_select #loading").hide(); }, "script");
} else {
manage_select_class($("#user_category_select select"), $(this).prev("select"), real_id, real_name);
}
});
// remove all next selects to generate new
function remove_select_after(object) {
if(object.length) {
var next = object.next("select");
object.remove();
if(next.length) remove_select_after(next);
}
}
// remove all ids and names and add to current one
// since there is just one category value to send
function manage_select_class(remove, assign, id, name) {
remove.attr("name", ""); remove.attr("id", "");
assign.attr("name", name); assign.attr("id", id);
}
get_nested_categories.js
$("#user_category_select").append("<%= escape_javascript(select :not, :selected, category_children(@categories), { :include_blank => true }) %> ");
I am sure that someone could re-factor some code better, especially JS, so fell free to post it in comments