Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Henrique Barcelos

[Resolvido] Script para manipulação de AJAX

Recommended Posts

Boa noite, galëre...

 

Nos úlitmos meses dei um ugrade nos meus scripts e tá ficando tão legal que decidi compartilhar, agora que não só eu posso entender, mas qualquer um Imagem Postada

 

Pra quem não viu ainda, este outro script é um plug-in jQuery para editar o conteúdo de uma tag html: myEditable 3.0

 

Neste tópico, vou lhes apresentar o meu script para manipulação de AJAX, que simplifica bastante o uso desta maravilhosa ferramenta da web...

 

Há algum tempo atrás, antes de começar a desenvolver este tipo de script, notava o quão repetitivas eram as funções Javascript que eu escrevia.

Tenho arquivos .js aqui com 80kB, a maior parte de requisições AJAX e validações.

 

Antes mesmo de começar a aprender sobre bibliotecas, como jQuery, script.a.culo.us, etc, decidi usar o [pouco] conhecimento que tinha sobre JSON para implementar uma classe que servisse ao propósito de simplificar ao máximo as requisições AJAX nas minhas páginas...

 

Saiu uma versão 1.0 beta, ainda meio lambancenta, resolvi nem compartilhar.

 

Passado algum tempo, depois de estudar a fundo JSON, fui melhorando essa classe e agora ela se encontra na versão 4.0a, que eu considerei bem estável e sólida, sendo assim, hora de 'por na roda'...

 

Mas chega de papo, vamos ao que interessa.

 

Segue o código:

var myAjax = function(preferences){	this.xmlHttpRequest = null;	for (var i in myAjax.defaults) {		this[i] = myAjax.defaults[i];	}		this.config(preferences);};myAjax.defaults = {	/* loadingID:		ID do elemento a ser exibido enquanto a requisição é processada [padrão = 'myAjaxLoading']	 * loadingContent: 	Conteúdo do elemento a ser exibido enquanto a requisição é processada (versões anteriores: 'contentLoading')	 * loadingWrapper: 	Elemento ou ID do elemento pai do elemento loading [padrão = tag BODY]	 * showLoading: 	Mostrar ou não a mensagem de carregando na tela	 * timeout:			Tempo (em ms) para remover a mensagem de carregando...	 * mode: 			Modo da requisição [TEXT, XML ou JSON]	 * method:			Método da requisição [GET ou POST]	 * data: 			Dados a serem enviados na requisição (versões anteriores: 'params')	 * complete:		Função ou array de funções a serem executadas ao fim da requisição	 * showResponse:	Mostrar ou não a resposta da requisição diretamente no elemento HTMLObject	 * filterResponse:	Mostrar somente o conteúdo (innerHTML) ou o valor do elemento com ID informado aqui [padrão: conteúdo da tag BODY]	 * HTMLObject:		Elemento ou ID do elemento no qual a resposta será exibita	 * url:				A URL da pagina a ser carregada	 * headres: 		Headers a serem enviados junto com a requisição	 */		loadingID: 'myAjaxLoading',	loadingContent: 'Carregando...',	loadingWrapper: 'body',	showLoading: true,	timeout: 500,		mode: 'TEXT',	method: 'GET',	data: 'ajax_request=' + true,		start: null,	complete: null,	stateChangeCallback: null,	jsonParse: null,	xmlParse: null,		showResponse: true,	filterResponse: null,	HTMLObject: null,		url: null,	headers: new Array(),		requisitionErrors: {		400: 'Erro #400: Bad request!',		403: 'Erro #403: Acesso proibido!',		404: 'Erro #404: Página não encontrada!',		408: 'Erro #408: Tempo limite atingido!',		500: 'Erro #500: Erro interno do servidor!',		504: 'Erro #504: Gateway offline!',		0: 'Erro de requisição desconhecido!'	}};myAjax.setDefaults = function(preferences){	if (typeof preferences == "object") {		for (var i in preferences) {			if (i in myAjax.defaults) {				myAjax.defaults[i] = preferences[i];			}		}	}};myAjax.handExceptions = function(msg){	throw new Error(msg);};myAjax.prototype = {	//Configurando as opções sem mexer nos valores padrão (a nível de objeto, não de classe)	config: function(preferences){		if (typeof preferences == "object") {			for (var i in preferences) {				if (i in this) {					this[i] = preferences[i];				}			}		}				//Configurando o elemento contâiner		if (this.loadingWrapper == 'body') {			this.loadingWrapper = document.getElementsByTagName('body')[0];		}		else if (typeof this.loadingWrapper == "string") {			this.loadingWrapper = document.getElementById(this.loadingWrapper);		}				//Configurando o método		if (typeof this.method == "string") {			this.method = this.method.toUpperCase();		}		else {			myAjax.handExceptions('Método inválido! Valores esperados: "GET" ou "POST"')		}				//Configurando o modo		if (typeof this.mode == "string") {			this.mode = this.mode.toUpperCase();		}		else {			myAjax.handExceptions('Modo inválido! Valores esperados: "TEXT" ou "XML" ou "JSON"')		}	},		//inicialização do objeto XMLxmlHttpRequest	init: function(){		//cria o objeto XMLxmlHttpRequest pra Firefox, Chrome, Opera, Safari, etc.		var xmlHttpRequest = null;		try {			xmlHttpRequest = new XMLHttpRequest();		} 				//cria o objeto XMLHttpRequest pra IE 6.0 e posteriormente para IE7+		catch (e) {			try {				xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");			} 						catch (e) {				xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");			}		}				if (!xmlHttpRequest) {			myAjax.handExceptions('O objeto XmlHttpRequest não pôde ser inicializado. Talvez haja suporte a AJAX no seu navegador.');		}				return xmlHttpRequest;	},		//Envia os headers da requisiçao	setHeaders: function(headers){		if (headers) {			if (typeof headers == 'object') {				if (headers.length) {					this.headers = this.headers.concat(headers);				}				else {					this.headers.push(headers);				}			}		}		if (typeof this.headers == "object") {			if (this.headers.length) {				for (var i = 0; i < this.headers.length; i++) {					var header = this.headers[i].header;					var value = this.headers[i].value;					if (header && value) {						this.xmlHttpRequest.setRequestHeader(header, value);					}				}			}		}	},		load: function(url, HTMLObject){		if (!url) {			myAjax.handExceptions('Você não informou a URL dá página a ser processada!');			return false;		}				if(typeof this.start == "function"){			this.start.call(this);		}				//Inicializando o objeto XMLHTTPRequest		this.xmlHttpRequest = this.init();				//Configurando o objeto HTML		this.HTMLObject = HTMLObject;		if (!this.HTMLObject) {			this.showResponse = false;		}				else {			if (typeof HTMLObject == 'string') {				this.HTMLObject = document.getElementById(HTMLObject);			}			else {				this.HTMLObject = HTMLObject;			}					}				this.data = this.generateQueryString(this.data);		if (!this.data.match('ajax_request')) {			this.data += "&ajax_request=" + true;		}				if (this.method == 'POST') {			//Se temos uma requisição POST, precisamos setar um Header e adicionar o parâmetro ajax_request			this.headers.push({				header: "Content-Type",				value: "application/x-www-form-urlencoded"			});		}		else {			//Se temos uma requisição GET, precisamos acidionar o parâmetro ajax_request à query string			var joinner = (url.toString().indexOf('?') == -1) ? '?' : '&';			url += joinner + this.data;		}				this.url = url;				this.xmlHttpRequest.open(this.method, this.url, true);		this.setHeaders();		this.xmlHttpRequest.send(this.data);				var self = this;				this.xmlHttpRequest.onreadystatechange = function(e){			self.stateChange.call(self);		}	},		get: function(url, HTMLObject, data){		this.method = 'GET';		this.data = data || this.data;		this.load(url, HTMLObject);	},		post: function(url, data, HTMLObject){		this.method = 'POST';		this.data = data;		this.load(url, HTMLObject);	},		generateQueryString: function(data){		var qs = '';		if (typeof data == 'object') {			qs = '';			this.queryStringEncode(data);			for (var i in data) {				qs += i + "=" + data[i] + "&";			}			qs = qs.replace(/&$/, "");		}		else if (typeof data == 'string') {			qs = data;		}		else {			myAjax.handExceptions('A variável que guarda o valor dos dados da requisição deve ser do tipo TEXTO ou OBJETO');		}		return qs;	},		queryStringEncode: function(data){		if (typeof data == "object") {			for (var i in data) {				data[i] = data[i].toString().replace(/&/, "**ampersand**");				data[i] = data[i].toString().replace(/+/, "**plus**");			}		}		return data;	},		stateChange: function(){		if(typeof this.stateChangeCallback == "function"){			this.stateChangeCallback.call(this, this.xmlHttpRequest.readyState);		}				if (this.xmlHttpRequest.readyState == 4) {			this.processing(false);			var status = this.xmlHttpRequest.status;			if (status == 200) {				this.handResponse();				this.callFunctions();			}			else {				var error = this.requisitionErrors[status];				myAjax.handExceptions(error);			}		}		else {			if (this.showLoading) {				this.processing(true);			}		}	},		processing: function(opt){		if (opt) {			var wrapper = this.loadingWrapper;			var divLoading = document.getElementById(this.loadingID);			if (!divLoading) {				divLoading = document.createElement("div");				divLoading.setAttribute("id", this.loadingID);				divLoading.innerHTML = this.loadingContent;				wrapper.insertBefore(divLoading, wrapper.firstChild);			} else {				divLoading.innerHTML = this.loadingContent;			}		}		else {			var self = this;			setTimeout(function(){				var divLoading = document.getElementById(self.loadingID);				if (divLoading) {					divLoading.parentNode.removeChild(divLoading);				}			}, self.timeout);		}	},		handResponse: function(){		var mode = this.mode;		if (typeof mode == "string") {			mode = mode.toUpperCase();			var response = null;						switch (mode) {				case 'TEXT':					response = this.getText();					break;				case 'JSON':					if (typeof this.jsonParse == "function") {						response = this.jsonParse.call(this, this.getJSON());					}					else {						myAjax.handExceptions('Não foi definida uma função de parsing JSON');					}					break;				case 'XML':					if (typeof this.xmlParse == "function") {						response = this.xmlParse.call(this, this.getXML());					}					else {						myAjax.handExceptions('Não foi definida uma função de parsing XML');					}					break;				default:					myAjax.handExceptions('Modo inválido! Valores esperados: "TEXT" ou "XML" ou "JSON"');					return false;			}						if (this.showResponse) {				if (this.HTMLObject) {					if (this.HTMLObject.nodeName == "INPUT" ||					this.HTMLObject.nodeName == "TEXTAREA" ||					this.HTMLObject.nodeName == "OPTION") {						this.HTMLObject.value = response;					}					else {						this.HTMLObject.innerHTML = response;					}				}				else {					myAjax.handExceptions("Elemento contâiner inválido ou inexistente!");				}			}					}		else {			myAjax.handExceptions('Modo de requisição inválido!')		}	},		//Faz a chamada das funções quando a requisição for completada	callFunctions: function(){		var complete = this.complete;		if (complete != null) {			if (typeof complete == "object") {				for (var i = 0; i < complete.length; i++) {					if (typeof complete[i] == "function") {						complete[i].call(this);					}					else {						myAjax.handExceptions("Função Inválida!");					}				}			}			else if (typeof complete == "function") {				complete.call(this);			}			else {				myAjax.handExceptions("Função inválida ou inexistente!");			}		}	},		getText: function(){		var response = this.xmlHttpRequest.responseText;		return response;	},		getJSON: function(){		return eval(this.getText());	},		getXML: function(){		return this.xmlHttpRequest.responseXML;	}}

 

O Básico

P: Qual a tarefa mais básica quando se fala de AJAX?

R: Faz a requisição e mostra a resposta em um elemento

 

Antes eu ia lá, pra cada requisição diferente o maluco aqui fazia tudo na unha: instancia o objeto XMLHTTPRequest, seta os headers, abre a requisição, envia, verifica o processamento e retorna o resultado... UFA Imagem Postada

 

Com a classe myAjax isso tudo já está feito, você só precisa informar o necessário:

 

 

var ajax = new myAjax();ajax.load("PAGINA.HTML", "ID DO ELEMENTO");
O método load faz por padrão uma requisição com método GET da página "PAGINA.HTML" e mostra a resposta dentro do elemento de ID "ID DO ELEMENTO"...

Importante ressaltar que não se deve incluir a tralha (#) nesse ID, pois o script utiliza-se da função document.getElementByID(), e não usa seletores CSS como nas bibliotecas mais comuns...

 

Alternativamente, ao invés de informar o ID do elemento, você pode informar o próprimo elemento (um objeto HTMLElement), já previamente selecionado...

 

 

Os métodos GET e POST

 

A função load, como informado, realiza por padrão uma requisição GET. Para facilitar a leitura de código, para que o programador saiba exatamente o que está fazendo, há um alias para essa função, a função get():

 

 

 

var ajax = new myAjax();ajax.get("PAGINA.HTML", "ID DO ELEMENTO");
Este código faz a mesma coisa do exemplo anterior.

 

Já para fazermos uma requisição POST, antes precisaríamos além de fazer todas aquelas operações que já citei, setar um header específico:

 

 

xmlHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
Trabalho demais né?

Eu demorei uns 8 meses pra decorar esse header aí...

 

Bom, chega disso... Agora é só fazer assim:

 

 

var ajax = new myAjax();ajax.post("PAGINA.HTML", "propriedade1=valor&propriedade2=valor" , "ID DO ELEMENTO");
Percebam que há agora um 3º argumento.

Numa requisição POST, você deve enviar os dados pela mesma, do contrário, não faz nenhum sentido existir uma requisição POST.

Este método é útil para o envio de formulários, pois apresenta uma maior segurança.

 

Note a ordem dos argumentos, ela é importante:

 

 

 

[*]Página a ser carregada

[*]Dados da requisição

[*]ID do elemento ou o próprio elemento no qual a resposta será exibida

Os dados da requisição podem ser no formato de uma query_string (igual ao que se coloca depois do '?' em um link, sem o '?') ou um objeto JSON, no caso:

 

 

var dados = { propriedade1: 'valor1', propriedade2: 'valor2', propriedade3: 'valor3',}//equivale àvar dados = "propriedade1=valor2&propriedade2=valor2&propriedade3=valor3";//e fazemos a requisiçãovar ajax = new myAjax();ajax.post('pagina.html', dados, 'id do elemento');

Executando uma função quando a requisição é iniciada ou completada

 

A maior das dúvidas sobre AJAX para aqueles que estão começando é:

P: Como eu executo uma função para agir sobre um elemento que foi carregado via AJAX?

R: Você deve esperar o fim da requisição e só aí chamar tal função

 

Com este script, não precisa verificar o fim da requisição nem nada, é só informar o que você deseja fazer:

 

 

var ajax = new myAjax({ complete: function(){ alert('Fim da requisição'); }});ajax.get('pagina.html', 'id do elemento');
Iniciamos aqui a configuração do nosso objeto antes de instanciá-lo...

A propriedade complete deve receber uma função, ou um array de funções para se executar assim que a requisição se completar...

 

Neste exemplo, assim que a requisição terminar, será exibido um alert na tela.

 

Caso queira executar uma função já definida, apenas informe o nome da mesma para executá-la quando a requisição terminar.

 

var ajax = new myAjax({ complete: alerta});ajax.get('pagina.html', 'id do elemento');function alerta(){ alert('Fim da requisição');}
Importante: NÃO coloque parênteses após o nome da função

 

var ajax = new myAjax({ complete: alerta() //ERRADO!!!!!!!!!!!!!!!!!!!});ajax.get('pagina.html', 'id do elemento');function alerta(){ alert('Fim da requisição');}
Na mesma linha de raciocínio, é possível informar um array de funções para se executar:

 

 

var ajax = new myAjax({ complete: [alerta, confirma]});ajax.get('pagina.html', 'id do elemento');function alerta(){ alert('Fim da requisição');}function confirma(){ confirm('Deseja continuar?');}
Para executar uma função assim que a requisição é iniciada, use a propriedade start, que deve receber uma única função como parâmetro, arrays de funções não funcionam para esta propriedade.

 

Passou despercebido pois é raramente usada... Um FIX para a próxima versão Imagem Postada

 

 

Não mostrar a resposta da requisição diretamente em um elemento

 

Por vezes, não queremos exibir a resposta da requisição diretamente em um elemento. Para fazer isso há 2 maneiras:

 

 

 

[*]Configurando

var dados = {propriedade: valor}var ajax = new myAjax({ complete: function(){ alert('Fim da requisição'); }, showResponse: false});ajax.post('pagina.html', dados, 'id do elemento');
Note que configuramos a propriedade showResponse com o valor false, assim a resposta não será exibida no elemento

[*]Omitindo o parâmetro 'ID do Elemento' nos médotos get, post e load

 

Esta opção é mais lógica e intuitiva: se não quisermos que a resposta seja exibida no elemento, porque devemos informá-lo?

var dados = {propriedade: valor}var ajax = new myAjax({ complete: function(){ alert('Fim da requisição'); }});ajax.post('pagina.html', dados);

Manipulando a resposta de modo avançado

 

Dependendo da resposta obtida do servidor, podemos desejar executar funções diferentes.

Como pegamos o valor da resposta do servidor?

 

 

 

var dados = {propriedade: valor}var ajax = new myAjax({ complete: function(){ alert(this.getText()); }}); ajax.post('pagina.html', dados);
Com o método getText(), podemos saber exatamente a resposta do servidor.

 

 

 

 

var dados = {propriedade: valor} var ajax = new myAjax({ complete: function(){ var resposta = this.getText(); if(resposta == "Ok"){ //faz alguma coisa... } else { //faz outra coisa... } } }); ajax.post('pagina.html', dados);

Outros modos de requisição

 

Além de texto puro, a requisição pode retornar um XML ou JSON...

Para fazê-lo, precisamos alterar a propriedade mode:

 

 

 

 

 

var dados = {propriedade: valor} var ajax = new myAjax({ mode: 'XML', xmlParse: function(responseXML){ //faz algo com o XML carregado } }); ajax.get('arquivo.xml');
Não adianta nada só fazer a requisição XML, precisamos fazer alguma coisa com o XML retornado.

Assim, quando o modo é XML, você é obrigado a setar uma função para a propriedade xmlParse, a qual recebe como parâmetro o XML retornado

 

Análogo para o modo JSON, no qual você precisa setar a uma função para a propriedade jsonParse.

 

 

De olho na requisição

 

Talvez a maior fama das apliações AJAX seja por elas poderen exibir uma mensagem de carregando na tela enquanto a requisição não se completa.

O myAjax já faz isso por padrão. Ele adiciona à tag BODY um elemento (div) com ID 'myAjaxLoading' para que você possa modificar sua aparência através de CSS ou mesmo Javascript.

 

Acha chato esse tipo de mensagem? Desative-a:

 

 

var ajax = new myAjax({ showLoading: false }); ajax.get('arquivo.html', elemento);
Gostaria de alterar o texto dessa mensagem? Colocar uma imagem quem sabe?

Acha chato esse tipo de mensagem? Desative-a:

 

var ajax = new myAjax({ loadingContent: '<img src="loading.gif" alt="carregando"/>' }); ajax.get('arquivo.html', elemento);
Quer adicionar esta mensagem não à tag BODY, mas a um elemento específico?

 

var ajax = new myAjax({ loadingWrapper: document.getElementByID("container") }); ajax.get('arquivo.html', elemento);
Adiciona a mensagem de carregando ao elemento cujo ID seja 'container'

 

 

Opções adicionais

 

Algumas outras opções, não tão usadas, mas úteis às vezes:

 

 

timeout: 2000 //Tempo, em milissegundos
O tempo que a mensagem de carregando fica na tela após a requisição ter terminado

Às vezes a requisição ocorre tão rápido [principalmente quando estamos rodando a aplicação localmente] que nem enxergamos a mesagem de carregando...

Esta propriedade serve para retardar a remoção da mensagem...

 

 

 

 

headers: {header: 'Pragma', value: 'no-cache'}//ou...headers: [{header: 'Pragma', value: 'no-cache'}, {header: 'Content-type', value: 'text/html'}]
De vez em quando, queremos enviar algum header para a requisição.

Podemos alterar a propriedade headers, inserindo um objeto ou um array de objetos com as propriedades header [o nome do header] e value [o seu valor]

 

Setando Padrões

 

Imagine que você deseja exibir uma mensagem de carregando padrão...

Teria que fazer a configuração para todas as requisições?

 

 

 

 

var ajax = new myAjax({ loadingContent: '<img src="loading.gif" alt="carregando"/>' }); ajax.get('arquivo.html', elemento);var ajax2 = new myAjax({ loadingContent: '<img src="loading.gif" alt="carregando"/>' });ajax.get('arquivo2.html', elemento);//...
Anti-prático não?

Como futuro engenheiro, tenho que usar a lei do menor esforço Imagem Postada

Pra que fazer isso em todas as requsições?

 

A solução: o método estático setDefaults:

 

 

window.onload = function(){ myAjax.setDefaults({ loadingContent: '<img src="loading.gif" alt="carregando"/>' });}//ou, usando jQuery$(document).ready(function(){ myAjax.setDefaults({ loadingContent: '<img src="loading.gif" alt="carregando"/>' });});
Agora, toda e qualquer requisição ajax mostrará a mensagem de carregando acima, a menos que você configure para ser diferente.

 

 

Bem, é isso aí...

 

Até hoje não de deparei com nenhuma situação que não pudesse utilizar este script para manipulação de AJAX.

 

É claro que as bibliotecas javascript também tem seus próprios métodos para fazer, mas é legal ver que dá pra se fazer tudo isso utilizando apenas o core do javascript Imagem Postada

 

 

Iss-ss-sso é-é tu-tu-tu-do pe-pes-pes-soal Imagem Postada

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.