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.

1 comentario:

danimataonrails dijo...

Como aportación adicional hay que comentar que el funcionamiento del cambio de contenido HTML no funciona igual en los distintos navegadores. Mientras que en Firefox cualquier elemento tiene un atributo innerHTML que sobreescribir, en Internet Explorer sólo DIV y SPAN lo poseen. Por esta razón, es recomendable que es objeto sobre el que se invoca el cambio de contenido sea de uno de estos tipos, DIV o SPAN.

De esta manera, sobre el ejemplo citado en el entrada, podemos recubrir el SELECT dependiente con un tag -SPAN id="span_for_select"- y hacer que observe_field tenga como parámetro :update el valor 'span_for_select'. Finalmente, en _combo_por_empresa.rhtml, en lugar de generar los OPTIONS del SELECT dependiente, generaremos el SELECT completo (manteniendo el ID para que continúen funcionando futuras actualizaciones).