Eustáquio Rangel

Desenvolvedor, pai, metalhead, ciclista

Rails: Alterando as OPTIONs dos SELECTs

Publicado em Developer


Ontem estava dando uma mão à noite para a minha esposa, que é webdesigner e está aprendendo a programar agora, adivinhem, com Rails (e adivinhem quem é o suporte-técnico-oficial-24-horas-VIP dela, tô ferrado) e ontem ela teve um probleminha para preencher alguns SELECTs. Vou descrever uma situação parecida com a que ela teve:

Até aí, tudo bem, mas surgiram uns probleminhas:

Vou tentar ilustrar um pouco o problema e a solução com código (onde juntei tudo em um lugar só apenas para fins didáticos, separem seus controladores certinho!). Gerei um controlador chamado Geral com as ações (métodos, dã!) estados, cidades e novo, e um monte de hashes e arrays para fazer uma simulação de dados vindo do banco de dados.

A jogada que fiz foi usar o método call, que chamada uma função JavaScript na página que requisitou a chamada AJAX. Essa função (porcamente inserida ali dentro da ação, para efeito do exemplo - se forem usar a coloquem em um arquivo .js) recebe o id do SELECT que queremos atualizar e o array com os dados a serem inseridos, faz um "limpa" no SELECT e adiciona as OPTIONs novas criadas a partir dos valores do array enviado. O controlador fica assim:

class GeralController < ApplicationController
  def estados
    @paises_estados = {1=>[['SP',1],['MG',2]],2=>[['J1',3],['J2',4]],
3=>[['C1',5],['C2',6]]}
    render :update do |page|
      page.call 'fill', 'estados', @paises_estados[params[:id].to_i]
      page.call 'fill', 'cidades', []
    end
  end

  def cidades
    @estados_cidades = {1=>[['Mirassol',1],['Rio Preto',2]],
2=>[['Belo Horizonte',3],['Divinópolis',4]],3=>[['Tokio',5]],
4=>[['Osaka',6]],5=>[['Alberta',5]],6=>[['Vancouver',6]]}
    render :update do |page|
      page.call 'fill', 'cidades', @estados_cidades[params[:id].to_i]
    end
  end

  def novo
    @paises = [['Brasil',1],['Japão',2],['Canadá',3]]
  end
end

Ali no controlador tem uma jogada de enviar um array vazio de cidades toda vez que são retornados novos estados, evitando a inconsistência de ficar com as cidades selecionadas anteriormente preenchidas. E a view novo, já com a função fill, fica assim:

<script type="text/javascript">
function fill(id,val){
	var select = $(id);
	var length = select.length;
	for(var i=0; i<length; i++)
		select.remove(0);

	if(val.lenght<=0)
		return;
	select.appendChild(document.createElement("option"));

	val.each(function(opt){
		var option 		= document.createElement("option");
		option.text 	= opt[0];
		option.value 	= opt[1];
		select.appendChild(option);
	})    
}
</script>
<form>
  <p>
    <label for="paises">Países</label>
    <select id="paises">
      <option></option>
      <%= options_for_select(@paises) %>
    </select>
  </p>
  <p>
    <label for="estados">Estados</label>
    <select id="estados">
    </select>
  </p>
  <p>
    <label for="cidades">Cidades</label>
    <select id="cidades">
    </select>
  </p>
  <p id="status"></p>
  <%= observe_field 'paises', :url=>{:action=>'estados'}, :with=>'id' %>
  <%= observe_field 'estados', :url=>{:action=>'cidades'}, :with=>'id' %>
</form>

Eu procurei no Prototype e não vi muita coisa para se lidar com SELECTs, por isso fiz algumas coisas meio "na unha" ali na função, como apagar os elementos e criar as OPTIONs, se alguém souber um jeito direto no Prototype me envie um email que eu atualizo o código. Estava muito tarde ontem e eu não estava com saco de ficar fuçando demais na API do Prototype não (apesar de ter melhorado bastante, ainda fica devendo uma busca, tem muita coisa lá).

Com essa solução evitei ficar removendo e inserindo o SELECT que quero popular e evitando quaisquer problemas relacionados à isso.




Comentários

Comentários fechados.

Sem nenhum comentário.

Artigos anteriores