tadarank afiliados

29 janeiro, 2007

InnerHTML em Select Option

Opa.

Seguindo uma postagem do Julio Greff sobre o velho problema (bug) do IE ao trabalhar com innerHTML e a tag select, vou mostrar aqui minha solução que eu já tinha feito na época da minha função simples pra ajax.

Edit 28/08/2007: Segunda versão corrigindo bugs pra ativar o selected, classes e styles no IE também

Pequena explicação do problema: às vezes, é necessário agente preencher uma tag select com options através de innerHTML. Pra variar, o IE dá problema com isso. Tá certo que innerHTML não é uma propriedade DOM padrão, mas se o Internet Explorer decidiu implementar ela, deveria, pelo menos, ter implementado direito hehe. Bah, deixa de reclamação mico.

Exemplo:

document.getElementById("meu_select").innerHTML = "<option value='1'>não</option> <option value='2'>funfa</option>"; 

O script acima deveria colocar dentro da select chamada "meu_select" duas opções ("não" e "funfa"). Só que isso não funfa no IE. O jeito certo então é adicionar através de appendChild!!!

Mas, calma, não se desespere, não será necessário você ficar quebrando a cabeça com infinitos appendChild. O Mico resolveu o problema pra você. Basta adicionar minha função abaixo no seu script e chamá-la passando 2 parâmetros: o ID do select que você quer preencher e o innerHTML que você quer colocar dentro deste select.

A função vai cuidar de tudo, como se você estivesse setando através da propriedade innerHTML mesmo, inclusive os atributos do option.

Exemplo de uso (baseado no exemplo anterior que não funfava):

var inner = "<option value='1'>Agora</option> <option value='2'>funfa</option>"; 
select_innerHTML(document.getElementById("meu_select"),inner);

A função mágica que faz isso. Adicione copie no seu script:

function select_innerHTML(objeto,innerHTML){
/******
* select_innerHTML - corrige o bug do InnerHTML em selects no IE
* Veja o problema em: http://support.microsoft.com/default.aspx?scid=kb;en-us;276228
* Versão: 2.1 - 04/09/2007
* Autor: Micox - Náiron José C. Guimarães - micoxjcg@yahoo.com.br
* @objeto(tipo HTMLobject): o select a ser alterado
* @innerHTML(tipo string): o novo valor do innerHTML
*******/
    objeto.innerHTML = ""
    var selTemp = document.createElement("micoxselect")
    var opt;
    selTemp.id="micoxselect1"
    document.body.appendChild(selTemp)
    selTemp = document.getElementById("micoxselect1")
    selTemp.style.display="none"
    if(innerHTML.toLowerCase().indexOf("<option")<0){//se não é option eu converto
        innerHTML = "<option>" + innerHTML + "</option>"
    }
    innerHTML = innerHTML.toLowerCase().replace(/<option/g,"<span").replace(/<\/option/g,"</span")
    selTemp.innerHTML = innerHTML
      
    
    for(var i=0;i<selTemp.childNodes.length;i++){
  var spantemp = selTemp.childNodes[i];
  
        if(spantemp.tagName){     
            opt = document.createElement("OPTION")
    
   if(document.all){ //IE
    objeto.add(opt)
   }else{
    objeto.appendChild(opt)
   }       
    
   //getting attributes
   for(var j=0; j<spantemp.attributes.length ; j++){
    var attrName = spantemp.attributes[j].nodeName;
    var attrVal = spantemp.attributes[j].nodeValue;
    if(attrVal){
     try{
      opt.setAttribute(attrName,attrVal);
      opt.setAttributeNode(spantemp.attributes[j].cloneNode(true));
     }catch(e){}
    }
   }
   //getting styles
   if(spantemp.style){
    for(var y in spantemp.style){
     try{opt.style[y] = spantemp.style[y];}catch(e){}
    }
   }
   //value and text
   opt.value = spantemp.getAttribute("value")
   opt.text = spantemp.innerHTML
   //IE
   opt.selected = spantemp.getAttribute('selected');
   opt.className = spantemp.className;
  } 
 }    
 document.body.removeChild(selTemp)
 selTemp = null
}

Bugs? Grita nos comments ae. Dúvidas? Joga no fórum e me avisa.
Não se esqueça de conferir também a solução do Julio para este problema.

Gostou da dica acima? Então clica nos botões de compartilhamento abaixo e me ajude a dica a subir no Google.

19 comentários:

  1. É, não é só no XHTML e CSS que a Microsoft faz bonito, ela consegue ser diferente também no JS. Haja paciência, né? Magnífica solução!
    Estou comeeçaando (a passos de tartaruga) a minha aprendizagem de AJAX, mas o que mais me intriga, de tudo isso, é o fato de perdermos tanto tempo arrumando coisinhas pois o IE faz tudo como ele mesmo quer. É uma lástima, mas "ESTAMOS AQUI PRA ISSO".

    Abraços!

    ResponderExcluir
  2. Engenhoso... Infelizmente, o tal do innerHTML é uma tentação. E muito mais rápido do que appendChild. E nem pra implementar direito, como o mico disse. Funciona legal, só não deixa a W3C ver isso...

    ResponderExcluir
  3. Fala Mico, beleza?
    Cara hoje vi este post e o do Julio. Uso outra forma para preencher os selects, option a option, usando o método add, nativo do objeto select.
    Talvez interesse ver outra forma...

    function addOption(selec,val,tex) {
    var opt = document.createElement('option');
    opt.value = val;
    opt.text = tex;
    try { selec.add(opt, null); } // NS FF
    catch(e) { selec.add(opt); } // IE
    }

    Abraço, Cau

    ResponderExcluir
  4. @rafael
    A MS fez muito no passado pelo JavaScript e pelo CSS, mas hoje em dia tá manezando ao não respeitar os padrões

    @Julio
    hehe, é verdade. De qualquer forma o innerHTML não é padrão, e dentro da minha função eu uso o innerHTML.
    Mas é só uma facilidade ao mexer com o select. heheh

    @Cau
    Beleza, valeu cau. Depois insiro esta nova forma dentro da minha função pra ver se fica melhor :)

    ResponderExcluir
  5. Tem essa tb, que é padrão para todos, sem isso de ifs //para IE, //para FF, Opera...

    function addOption(id, sText, sValue) {
    var obj = document.getElementById(id);
    obj.options[obj.length] = new Option(sText, sValue);
    }

    Falou,
    Fabrício Magri

    ResponderExcluir
  6. Daew Micox..
    Eu criei esta funcao aqui, baseando-me no mootools, acho que ela resolve o problema do innerHTML para select do Internet Explorer..
    pelo menos pra mim resolveu!

    Vou colocar aqui duas versoes:
    1ª - baseada no mootools
    2ª - convertida para ser usada sem o mootools

    Obs: Quando for copiar a funcao, substitua a string de valor (TAG SELECT) pela tag select , e onde esta (TAG /SELECT) pela tag /select .
    *Mudanca feita porque o blog nao aceita tag select no comentario.

    Testa aew e me diz se ela faz o mesmo que a sua, valeu pela funcao, tive a ideia de fazer a minha quando vi a sua!

    id : id do select.
    html: html com as tags option.

    1ª:

    function innerSelect(id,html)
    {
    var sel = $(id);
    html = '(TAG SELECT)'+html+'(TAG /SELECT)';
    var temp = new Element('div');
    temp.setHTML(html);sel.setHTML('');
    temp.getElements('option').each( function(opt){opt.injectInside(sel);} );
    }

    2ª:
    function innerSelect(id,html)
    {
    var sel = document.getElementById(id);
    html = '(TAG SELECT)'+html+'<(TAG /SELECT)';
    var temp = document.createElement('div');
    temp.innerHTML = html;
    sel.innerHTML = '';
    var options = temp.getElementsByTagName('option');
    while (options.length)
    {
    sel.appendChild(options[i]);
    }
    }

    ResponderExcluir
  7. @Fabricio e Roberson
    As funções de vocês fazem QUASE a mesma coisa. Só faltou pegarem os atributos dos options tipo "selected".

    Valeus pelas contribuições ae.

    ResponderExcluir
  8. Nao micox.. tipow se vc passar la o option id="opt1" selected="selected" value="32"> Nao Funfa /option>
    corrigindo as tags ali eh claro..
    ele vai pegar todos os atributos passados (no caso id, selected, e value.. contanto q seja passado assim na html!
    esclarecido?
    abraços..

    ResponderExcluir
  9. Companheiro, tive o mesmo problema que você ao preencher um SELECT com Ajax. A Microsoft se supera a cada dia.
    Sua solução foi muito boa.

    ResponderExcluir
  10. @roberson
    Demorei pra responder mas saquei sua explicação. Valeus.

    ResponderExcluir
  11. a "função mágica" funcionou perfeitamente no ie mas nao funcionou no firefox. alguem tem alguma ideia?

    ResponderExcluir
  12. TIRE O TOLOWERCASE pq ele converte o texto para minusuulo

    ResponderExcluir
  13. Também tirei o lowercase pro texto ficar normal... fora isso, muito boa a função! valeu

    ResponderExcluir
  14. Galera tow com uma grande dúvida: o IE 7 diz que o meu select_mes não está definido:

    ...

    var linha = tabela.insertRow(ultima_linha);
    var celula_nascimento = linha.insertCell(2);

    ...

    //// select do mês
    var select_mes = document.createElement('select');
    select_mes.name = 'dep_mes' + iteracao;
    select_mes.id = 'dep_mes' + iteracao;
    select_mes.options[0] = new Option('01', '1');
    select_mes.options[1] = new Option('02', '2');
    select_mes.options[2] = new Option('03', '3');
    select_mes.options[3] = new Option('04', '4');
    select_mes.options[4] = new Option('05', '5');
    select_mes.options[5] = new Option('06', '6');
    select_mes.options[6] = new Option('07', '7');
    select_mes.options[7] = new Option('08', '8');
    select_mes.options[8] = new Option('09', '9');
    select_mes.options[9] = new Option('10', '10');
    select_mes.options[10] = new Option('11', '11');
    select_mes.options[11] = new Option('12', '12');
    select_mes.onchange = function(){
    muda_campo_oculto ( 'dep_mes' + iteracao, 'dep_mes_hidden' + iteracao );
    };
    celula_nascimento.appendChild(select_mes);


    Fiz um select_dia exatamente igual a esse e o adicionei também a celula_nascimento e funcionou!

    ResponderExcluir
  15. Eu acho que o problema pode estar é no celula_nascimento

    ResponderExcluir
  16. Poxa, Micox eu fiz tudo certo nele....ou não? Do que vc suspeita ??

    ResponderExcluir
  17. Provavelmente o insertCell não retornou um (1) objeto HTML. Sacou?

    ResponderExcluir
  18. Mas a função começa assim:

    adicionaLinhaTabela = function() {
    teste ();
    }

    function teste()
    {
    var tabela = document.getElementById('dependentes');
    var ultima_linha = tabela.rows.length;

    var iteracao = ultima_linha - 1;
    var linha = tabela.insertRow(ultima_linha);

    // nro
    var celula_nro = linha.insertCell(0);
    var texto = document.createTextNode(iteracao);
    celula_nro.appendChild(texto);

    // nome
    var celula_nome = linha.insertCell(1);
    var el = document.createElement('input');
    el.type = 'text';
    el.name = 'dep_nome' + iteracao;
    el.id = 'dep_nome' + iteracao;
    el.size = 30;
    el.width = 80;
    //el.onkeypress = keyPressTest;
    celula_nome.appendChild(el);

    // data de nascimento
    var celula_nascimento = linha.insertCell(2);
    //// select do dia
    var select_dia = document.createElement('select');
    select_dia.name = 'dep_dia' + iteracao;
    select_dia.id = 'dep_dia' + iteracao;
    select_dia.options[0] = new Option('01', '1');
    select_dia.options[1] = new Option('02', '2');
    select_dia.options[2] = new Option('03', '3');

    // aqui vem o resto que já mostrei .......

    ResponderExcluir
  19. Parabéns pela dica, funfou de primeira comigo. Gostaria de contribuir, com uma alteração: é que o texto que aparecia no OPTION está ficando minúsculo. Eis a minha sugestão de alteração:
    ONDE TEM...
    if(innerHTML.toLowerCase().indexOf("<option")<0){//se não é option eu converto
    SUBSTITUIR POR
    if(innerHTML.search(/<option/i)<0){//se não é option eu converto

    E ONDE TEM...
    innerHTML = innerHTML.toLowerCase().replace(/<option/g,"<span").replace(/<\/option/g,"</span")
    SUBSTITUIR POR...
    innerHTML = innerHTML.replace(/<option/gi,"<span").replace(/<\/option/gi,"</span")

    É isso, substitui onde tinha toLowerCase

    ResponderExcluir

Resultado! Concursos