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.
É, 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!
ResponderExcluirEstou 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!
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...
ResponderExcluirFala Mico, beleza?
ResponderExcluirCara 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
@rafael
ResponderExcluirA 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 :)
Tem essa tb, que é padrão para todos, sem isso de ifs //para IE, //para FF, Opera...
ResponderExcluirfunction addOption(id, sText, sValue) {
var obj = document.getElementById(id);
obj.options[obj.length] = new Option(sText, sValue);
}
Falou,
Fabrício Magri
Daew Micox..
ResponderExcluirEu 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]);
}
}
@Fabricio e Roberson
ResponderExcluirAs funções de vocês fazem QUASE a mesma coisa. Só faltou pegarem os atributos dos options tipo "selected".
Valeus pelas contribuições ae.
Nao micox.. tipow se vc passar la o option id="opt1" selected="selected" value="32"> Nao Funfa /option>
ResponderExcluircorrigindo 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..
Companheiro, tive o mesmo problema que você ao preencher um SELECT com Ajax. A Microsoft se supera a cada dia.
ResponderExcluirSua solução foi muito boa.
@roberson
ResponderExcluirDemorei pra responder mas saquei sua explicação. Valeus.
a "função mágica" funcionou perfeitamente no ie mas nao funcionou no firefox. alguem tem alguma ideia?
ResponderExcluirTIRE O TOLOWERCASE pq ele converte o texto para minusuulo
ResponderExcluirTambém tirei o lowercase pro texto ficar normal... fora isso, muito boa a função! valeu
ResponderExcluirGalera tow com uma grande dúvida: o IE 7 diz que o meu select_mes não está definido:
ResponderExcluir...
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!
Eu acho que o problema pode estar é no celula_nascimento
ResponderExcluirPoxa, Micox eu fiz tudo certo nele....ou não? Do que vc suspeita ??
ResponderExcluirProvavelmente o insertCell não retornou um (1) objeto HTML. Sacou?
ResponderExcluirMas a função começa assim:
ResponderExcluiradicionaLinhaTabela = 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 .......
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:
ResponderExcluirONDE 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