quinta-feira, abril 10, 2008

Javascript: método apply()

O método apply() pode resolver o "problema do this", descrito aqui. As vezes o this refere-se ao objeto Window e não ao objeto que está instanciado. O código abaixo mostra este problema: o metodoA() informa o this corretamente, mas o metodoB() não (é um método privado, mas isso não seria motivo para esse comportamento).


Como solução, no metodoA(), realize a troca na linha 9 para:
_metodoB.apply(this);
Com isso, o método B será chamado "como se fosse chamado" pelo objeto informado no apply(), no caso o this "verdadeiro".

UPDATE1: se precisar atribuir o método em eventos onclick, por exemplo, siga o modelo abaixo:
objeto.onclick = a (this, "meumetodo");
function a (objeto, metodo) {return function () {objeto[metodo].apply(objeto)}}
UPDATE2: ATENCAO - se você passar um parâmetro para o método, o apply pára de funcionar!!!

É isso,
Tooper

obs: caso queira copiar o código, ele segue abaixo.


m = new Classe;
m.metodoA();

function Classe () {

this.metodoA = function () {
alert((this.location) ? "Window" : "Instancia");
_metodoB;
}

function _metodoB () {
alert((this.location) ? "Window" : "Instancia");
}

}

Simulando Ajax em browsers sem Ajax

É possível implementar Ajax sem utilizar Microsoft.XMLHTTP, Msxml2.XMLHTTP ou XMLHttpRequest (o título deste artigo é apenas para polemizar). Se você tiver que implementar sites que funcionem em IEs antigos (5.55 em windows antigos), esse artigo pode lhe interessar. Uma possível solução é:

  1. Criar um iframe dinamicamente
  2. Criar um form dentro deste iframe
  3. Preencher um campo deste form com os dados a serem enviados
  4. Dar submit no form
  5. Fazer um "loop" com setTimeout para verificar quando os dados voltaram do servidor.
Segue abaixo alguns exemplos de como fazer isso.

Criar iframe dinamicamente:
document.body.innerHTML += '<iframe name="meuframe"> </iframe>;

ou (solução menos bugada)

var f = document.createElement("iframe");
f.setAttribute("name", "meuframe");
document.body.appendChild(f);
Deixar o iframe invisível:
// Aplique o seguinte estilo no iframe
visiblility:hidden; // com display:none não funfa no FF
width:0px; height:0px; // para ele não ocupar espaço
border:0px; // se ficar com a borda, o FF exibe um bloquinho cinza
Criar form no iframe e preencher campo:
var html = '';
html += '<form name="meuform" method="post" action="minhaurl" >';
html += '
<textarea name="dados">' +mensagem + '</textarea >';
html += '</form>';
// NÃO use document.body.innerHTML, pois o FF não conseguirá dar submit()!
frames['meuframe'].document.write(html);

Dar submit no form:
frames['meuframe'].document.forms[0].submit();
Loop que aguarda retorno dos dados:
function etapa4 () {
// se ainda houver um form é o pq os dados ainda não chegaram
if (frames['meuframe'].document.forms.length == 1) {
window.setTimeout("etapa4()", 100);
return;
} else {
var r =
frames['meuframe'].document.body.innerHTML;
eval("meucallback(" + r + ");");
}
}

Esta solução verifica a cada 1/10 de segundo se os dados voltaram do servidor. Assim que os dados voltarem, a função meucallback() é chamada, sendo passado como parâmetro o resultado.

Obs importante:
É preciso dar um intervalo de tempo entre as etapas para que o navegador "perceba" os novos objetos. Para isso, acrescente no final de cada função (cada etapa deve estar em uma função diferente) um temporizador:
// ex de código a ser colocado no final da etapa2
window.setTimeout("chama_etapa_3()", 10);


Solução Testada em:
  • Windows XP (SP2)
  • FF: Firefox 2.0.0.7
  • IE: Internet Explorer 7 e Internet Explorer 5.55
Deixe um comentário!
:)