Fonte: Upload Assíncrono (iframe como AJAX) - 1 função simples - El Micox

Tô postando aqui uma função pra você fazer upload bem parecido com ajax (não é ajax!!). Função simples e fácil de usar.
Ela faz um upload assíncrono, ou seja, não recarrega a página toda (assim como o AJAX).
Quem usa alguns serviços do google como o GMail ou o GooglePages já conhece este recurso muito bem.

Upload usando apenas AJAX não é viável no ambiente da Internet pois, por motivos de segurança, os navegadores por padrão não dão acesso ao sistema de arquivos para o JavaScript (se quiser descobrir como ativar esta característica não padrão, leia aqui, mas acredito não ser muito útil ajax upload dessa forma).

Esta minha função utiliza técnicas que envolvem iframes, mas não vou dar explicações aqui não. Explicações sobre como desenvolvi a função serão dadas em um novo post. Este post aqui é só para o código.

Ah, sim, no próximo post mostrarei também uma função um pouco mais customizável já pra quem entende melhor de JavaScript.

Testado no Firefox 2.0, Internet Explorer 6.0 e Opera 9.1. Pelamordedeus, quem puder testar em outros navegadores aí e quiser citar a experiência, faça este favor à humanidade e cite a experiência nos comentários. Obrigado.

1) Coloque o código abaixo em um arquivo chamado micoxUpload.js

CODE
/* funçõezinhas padrão pra facilitar */
function $m(quem){
//apelido só pra não ficar repetindo o document.getElementById
return document.getElementById(quem)
}
function remove(quem){
quem.parentNode.removeChild(quem);
}
function addEvent(obj, evType, fn){
//o velho do elcio.com.br/crossbrowser
    if (obj.addEventListener)
        obj.addEventListener(evType, fn, true)
    if (obj.attachEvent)
        obj.attachEvent("on"+evType, fn)
}
function removeEvent( obj, type, fn ) {
  if ( obj.detachEvent ) {
    obj.detachEvent( 'on'+type, fn );
  } else {
    obj.removeEventListener( type, fn, false ); }
}
/* a que faz o serviço pesado */
function micoxUpload(form,url_action,id_elemento_retorno,html_exibe_carregando,html_erro_http){
/******
* micoxUpload - Submete um form para um iframe oculto e pega o resultado. Consequentemente pode
*               ser usado pra fazer upload de arquivos de forma assíncrona.
* Use a vontade mas coloque meu nome nos créditos. Licença Creative Commons.
* Versão: 1.0 - 03/03/2007 - Testado no FF2.0 IE6.0 e OP9.1
* Autor: Micox - Náiron JCG - elmicox.blogspot.com - micoxjcg@yahoo.com.br
* Parametros:
* form - o form a ser submetido ou seu ID
* url_action - url pra onde deve ser submetido o form
* id_elemento_retorno - id do elemento que irá receber a informação de retorno
* html_exibe_carregando - Texto (ou imagem) que será exibido enquanto se carrega o upload
* html_erro_http - texto (ou imagem) que será exibido se der erro HTTP.
*******/

//testando se passou o ID ou o objeto mesmo
form = typeof(form)=="string"?$m(form):form;

var erro="";
if(form==null || typeof(form)=="undefined"){ erro += "O form passado no 1o parâmetro não existe na página.\n";}
else if(form.nodeName!="FORM"){ erro += "O form passado no 1o parâmetro da função não é um form.\n";}
if($m(id_elemento_retorno)==null){ erro += "O elemento passado no 3o parâmetro não existe na página.\n";}
if(erro.length>0) {
  alert("Erro ao chamar a função micoxUpload:\n" + erro);
  return;
}

//criando o iframe
var iframe = document.createElement("iframe");
iframe.setAttribute("id","micox-temp");
iframe.setAttribute("name","micox-temp");
iframe.setAttribute("width","0");
iframe.setAttribute("height","0");
iframe.setAttribute("border","0");
iframe.setAttribute("style","width: 0; height: 0; border: none;");
/* Não usei display:none pra esconder o iframe
    pois tem uma lenda que diz que o NS6 ignora
    iframes que tenham o display:none */

//adicionando ao documento
form.parentNode.appendChild(iframe);
window.frames['micox-temp'].name="micox-temp"; //ie sucks

//adicionando o evento ao carregar
var carregou = function() {
   removeEvent( $m('micox-temp'),"load", carregou);
   var cross = "java script: ";
   cross += "window.parent.$m('" + id_elemento_retorno + "').innerHTML = document.body.innerHTML; void(0); ";
  
   $m(id_elemento_retorno).innerHTML = html_erro_http;
   $m('micox-temp').src = cross;
   //deleta o iframe
   setTimeout(function(){ remove($m('micox-temp'))}, 250);
  }
addEvent( $m('micox-temp'),"load", carregou)

//setando propriedades do form
form.setAttribute("target","micox-temp");
form.setAttribute("action",url_action);
form.setAttribute("method","post");
form.setAttribute("enctype","multipart/form-data");
form.setAttribute("encoding","multipart/form-data");
//submetendo
form.submit();

//se for pra exibir alguma imagem ou texto enquanto carrega
if(html_exibe_carregando.length > 0){
  $m(id_elemento_retorno ).innerHTML = html_exibe_carregando;
}

}


2) Inclua (chame) este arquivo no seu HTML

CODE
<script type="text/javascript" src="micoxUpload.js"></script>


3) Os parâmetros na hora de chamar a função são:

1. form - o form a ser submetido ou o ID de algum form que queira submeter.
2. url_action - url pra onde deve ser submetido o form. Tem a mesma função do parâmetro "action" de um form.
3. id_elemento_retorno - id do elemento que irá receber a informação de retorno.
4. html_exibe_carregando - Texto (ou imagem) que será exibido enquanto se carrega o upload
5. html_erro_http - Texto (ou imagem) que será exibido se der erro HTTP.

4) Pronto. Agora você várias formas de ativar o upload assíncrono. Vou exemplificar aqui 3 formas dentre as várias possíveis:

4.1) Uso básico. Você chama o upload a partir de um button (ou um input-type-button) em um form qualquer:

CODE
<legend>Uso b&aacute;sico</legend>
  <form>
    <input type="file" name="nome_qualquer" />
    <div id="recebe_up_basico" class="recebe">&nbsp;</div>
    <button onClick="micoxUpload(this.form,'upa.php','recebe_up_basico','Carregando...','Erro ao carregar'); return false;" type="button">testa</button>
  </form>
</fieldset>


4.2) Ativando o upload quando o campo file perde o foco (onblur):

CODE
<fieldset>
<legend>Uso no blur do input</legend>
  <form>
    <input type="file" name="nome_qualquer" onblur="micoxUpload(this.form,'upa.php','recebe_up_onblur','Carregando...','Erro ao carregar')" />
    <div id="recebe_up_onblur" class="recebe">&nbsp;</div>
  </form>
</fieldset>


4.3) Agora uma forma que deixará seu form/upload acessível mesmo que o javascript esteja desabilitado:

CODE
<fieldset>
<legend>Uso não intrusivo</legend>
    <form action="upa.php" target="_blank">
    <input type="file" name="nome_qualquer" onblur="micoxUpload(this.form,'upa.php','recebe_up_3','Carregando...','Erro ao carregar')" />
    <div id="recebe_up_3" class="recebe">&nbsp;</div>
  </form>
</fieldset>


Pronto. Customize aí agora e bora "uploadar". Bugs, erros, comenta ae.

Você gostou? Comente no fórum!

Comentários:

Ugo Stoso disse:

Grande Micox, abaixo está o código que estou usando para fazer o upload com a sua função, comigo não está funcionando, a página destino até é chamada mas os valores dos inputs não vão juntos.
A página Login.asp
CODE
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head>
        <title></title>
        <META http-equiv="Content-Type" content="text/html;" charset="iso-8859-1">
        <script src="js/micoxUpload.js" type="text/javascript"></script>
        <script src="js/micoxAjax.js" type="text/javascript"></script>
        <script language="javascript" type="text/javascript">
            function Logar()
            {   if(document.getElementById) { // Para os browsers complacentes com o DOM W3C.
                    var mensagem=document.getElementById('divMensagem');
                    var exibeResultado = document.getElementById('divMsg'); // div que exibirá a mensagem.
                    var login=document.getElementById('txtLogin');
                    var senha=document.getElementById('txtSenha');
                    //var CaminhoRetorno = 'include/Logar.asp?Login='+login.value+'&Senha='+senha.value;
                    //alert(CaminhoRetorno);return false;
                    var CaminhoRetorno = 'include/Logar.asp';
                    
                    if(!login.value||!senha.value)
                    {    alert('Você deve informar seu login e senha corretamente,\ntodos os campos são de preenchimento\nobrigatório.');
                        login.focus;
                        return false;}
                    else if(senha.length<8)
                    {    alert('Senha menor que o mínimo permitido\nverifique se você está digitando a senha correta\ne tente novamente.');
                        senha.value='';
                        senha.focus;
                        return false;}
                    else
                    {    mensagem.style.position='absolute';
                        mensagem.style.left=0;
                        mensagem.style.top=0;
                        //mensagem.grow({to:{height:50,width:200}});
                        //mensagem.fadeIn();
                        mensagem.style.display='block';
                        //ajaxGet(CaminhoRetorno,exibeResultado,true);
                        micoxUpload('frmLogin',CaminhoRetorno,'divMsg','Carregando...','Erro ao carregar'); return false;
                        //return true;
                    }
                }
            }
        </script>
    </head>
    <body id="body">
        <form id="frmLogin" action="include/Logar.asp" method="post">
            <div id="divLogar" style="Display:<%=divL%>;" class="Login">
                <table border="0" cellpadding="2" cellspacing="0" class="conteudo">
                    <tr><td colspan="2" align="center" valign="top" class="TituloTela">Informe sua Conta.</td></tr>
                    <tr><td>Login:</td>
                        <td><input type="text" name="txtLogin" id="txtLogin" maxlength="20" /></td>
                    </tr>
                    <tr><td>Senha:</td>
                        <td><input type="password" name="txtSenha" id="txtSenha" maxlength="10" /></td>
                    </tr>
                    <tr><td colspan="2">
                            <input type="button" id="btnEntrar" value="Função" onclick="return Logar();" />&nbsp;
                            <input type="submit" name="subEntrar" id="subEntrar" value="Submit">
                        </td>
                    </tr>
                </table>
            </div>
        </form>
    </body>
</html>

E a página logar.asp
CODE
<%Dim Login, Senha, teste1, teste2
    Login = Request.QueryString.Item("login")
    Senha = Request.QueryString.Item("senha")
    
    teste1 = Request.Form.Item("txtLogin")
    Senha = Request.Form.Item("txtSenha")
    
    Response.Write (login&" === "&Senha&" ---- "&teste1&" +++ "&teste2)
    Response.End%>
graduated.gif
Onde estou errando?
Um grande abraço. Desde já agradecendo a atenção e krak, suas funções são muito maneiras.

Micox disse:

Cara, procurei o elemento 'divMsg' no seu código e não encontrei.
Acredito que o problema esteja aí.

(Você está usando o Firefox pra exibir os erros de javascript ou té testando no IEca? )

Ugo Stoso disse:

QUOTE(Micox @ 23/03/2007 - 15:23) [snapback]67665[/snapback]
Cara, procurei o elemento 'divMsg' no seu código e não encontrei.
Acredito que o problema esteja aí.

(Você está usando o Firefox pra exibir os erros de javascript ou té testando no IEca? )



É q eu alterei várias vezes e devo ter me esquecido, estou usando o FireFox com o debug, mesmo com essa div o problema continua, essa div fica dentro da divMensagem. graduated.gif

Micox disse:

Então posta o novo código ae pra eu testar.

Ah, e faz o seguinte também: testa submeter o form sem usar minha função, pois pode ser que o erro esteja no ASP.

Ver o restante dos comentários no fórum (e aproveitar pra comentar também !).

Mais recentes em JavaScript e Ajax

Background randomico
Por JoneMulti - As vezes voce e pergunta "como é que aquele site...
Abandone o getelementbyid
Por Micox - “wtf mico? are you crazy?” - calma malucada, não estou...
Funções javascript equivalentes a funções
Por Micox - Php to javascript project: php.js...
Select dinâmico de estados e cidades
Por DGmike - Uma das dúvidas mais comuns para quem está começando...
Selecionar dinâmicamente um option de um select
Por Manito - Dica para quem fizer um form usando ajax...

Ver mais Artigos de JavaScript e Ajax.

Ver e retirar outras dúvidas no fórum Webly.

Alguns Direitos Reservados | RSS | O Fórum

Webly Portal e Fóruns - Internet + Humana | Design by ArthurHenrique.com