Hace tiempo ya conté cómo hacer combos dependientes con observe_field pero debe ser que me hago viejo y que me gusta hacer las cosas cada vez más pedrestres. En fin, que tirando a pelo de prototype, un poco de javascript y adaptando un controlador, conseguimos lo mismo de forma muy sencilla.
Supongamos dos modelos dependientes
class Country < ActiveRecord::Base
has_many :provinces
end
class Province < ActiveRecord::Base
belongs_to :country
end
enlazados en nuestro archivo de rutas como
map.resources :countries do |country|
country.resources :provinces
end
En a vista enlazamos países y provincias en dos combos...
<%= select :person, :country_id, countries_for_select.map{|c| [c.name, c.id]}, {}, {:onchange => "change_provinces('person_province_id', this.value);", :class => 'w150'} %>
<%= select :person, :province_id, provinces_for_select.map{|c| [c.name, c.id]}, {}, {:class => 'w150'} %>
donde countries_for_select y provinces_for_select nos dan los registro a pintar inicialmente en cada uno de ellos.
Sólo falta la función javascript change_provinces que haga la llamada Ajax y el repintado del combo cuyo ide recibe como primer parámetro...
function change_provinces(combo_id, country_id){
var url = '/countries/' + country_id + '/provinces';
var combo = $(combo_id);
for (var i = combo.options.length-1; i >= 0; i--){
combo.options[i] = null;
}
new Ajax.Request(url, {
method: 'get',
onSuccess: function(transport) {
prov_array = eval(transport.responseText);
for (var k = 0; k < prov_array.length; k++){
combo.options[k] = new Option(prov_array[k][1], prov_array[k][0]);
}
combo.options[0].selected = true;
},
onFailure:function(transport) {
}
});
}
... y finalmente adaptar provinces_controller
def index
@provinces = ...
if request.xhr?
render :text => @provinces.map{|province| [province.id, province.name]}.inspect
return
end
end
Y a correr. Ale, salud y rocanrol!
We shall go on to the end, we shall fight in France,
we shall fight on the seas and oceans,
we shall fight with growing confidence and growing strength in the air,
we shall defend our Island, whatever the cost may be,
we shall fight on the beaches,
we shall fight on the landing grounds,
we shall fight in the fields and in the streets,
we shall fight in the hills, we shall never surrender!"
Mostrando entradas con la etiqueta combo dependiente. Mostrar todas las entradas
Mostrando entradas con la etiqueta combo dependiente. Mostrar todas las entradas
viernes, 17 de julio de 2009
viernes, 17 de noviembre de 2006
Combos dependientes OnRails
Es muy común en la aplicaciones de hoy en día que sea necesario recargar los valores de un combo en función de lo que se haya seleccionado en uno previo.
La manera más fácil de conseguir este comportamiento en una página hecha con Rails es utlizar observe_field.
Funciona de la siguiente manera. Imaginemos el siguiente código para pintar el contenido de las tablas empresa y área.
<%= select 'usuario', 'empresa_id' , Empresa.find(:all).collect {|p| [ p.name, p.id ] } %>
<%= select 'usuario', 'area_id' , Area.find(:all).collect {|p| [ p.name, p.id ] } %>
Como las áreas son una subdivisión de una empresa queremos que el contenido del combo de áreas sea dependiente de la empresa seleccionada. Para ello codificaremos
<%= observe_field 'usuario_empresa_id', :url => @options.merge(:controller => '/areas', :action => 'combo_por_empresa'), :update => 'usuario_area_id', :with => 'combo_empresa_id' %>
Lo que estamos haciendo es controlar el evento onchange del primer combo de manera que su manejador invoque una petición ajax al controlador áreas con la acción combo_por_empresa y pasando el valor de ese primer combo en el parámetro combo_empresa_id.
Sólo nos queda incluir esta acción en el controlador con dos operaciones:
- las selección de los nuevos datos a pintar
@areas = Area.find(:all, :conditions => ['empresa_id = ?', params[:combo_empresa_id]])
- el render del fichero rhtml que pintará las nuevas opciones
return render(:partial => 'combo_por_empresa', :layout => false) if request.xhr?
Finalmente, en _combo_por_empresa.rhtml generamos el html con las nuevas opciones.
<%= options_for_select(@areas.collect {|p| [ p.name, p.id ]}) %>
Es muy recomendable mirar la documentación de observe_field en api.rubyonrails.org.
Salud.
La manera más fácil de conseguir este comportamiento en una página hecha con Rails es utlizar observe_field.
Funciona de la siguiente manera. Imaginemos el siguiente código para pintar el contenido de las tablas empresa y área.
<%= select 'usuario', 'empresa_id' , Empresa.find(:all).collect {|p| [ p.name, p.id ] } %>
<%= select 'usuario', 'area_id' , Area.find(:all).collect {|p| [ p.name, p.id ] } %>
Como las áreas son una subdivisión de una empresa queremos que el contenido del combo de áreas sea dependiente de la empresa seleccionada. Para ello codificaremos
<%= observe_field 'usuario_empresa_id', :url => @options.merge(:controller => '/areas', :action => 'combo_por_empresa'), :update => 'usuario_area_id', :with => 'combo_empresa_id' %>
Lo que estamos haciendo es controlar el evento onchange del primer combo de manera que su manejador invoque una petición ajax al controlador áreas con la acción combo_por_empresa y pasando el valor de ese primer combo en el parámetro combo_empresa_id.
Sólo nos queda incluir esta acción en el controlador con dos operaciones:
- las selección de los nuevos datos a pintar
@areas = Area.find(:all, :conditions => ['empresa_id = ?', params[:combo_empresa_id]])
- el render del fichero rhtml que pintará las nuevas opciones
return render(:partial => 'combo_por_empresa', :layout => false) if request.xhr?
Finalmente, en _combo_por_empresa.rhtml generamos el html con las nuevas opciones.
<%= options_for_select(@areas.collect {|p| [ p.name, p.id ]}) %>
Es muy recomendable mirar la documentación de observe_field en api.rubyonrails.org.
Salud.
Suscribirse a:
Entradas (Atom)