Artigos de Javascript.



JQuery e AJAX – Combo de Estado e Cidade

Essa semana precisei implementar uma solu√ß√£o de combo din√Ęmico de Estado / Cidade que carregasse as op√ß√Ķes das cidades de acordo com a escolha do estado. Obviamente teria que usar Ajax (JQuery) e o Json (JavaScript Object Notation) que √© um formato leve de troca de dados (fonte: http://www.json.org/).

Fiz uma pesquisa r√°pida na NET e de cara encontrei um excelente artigo de Davi Ferreira: “Populando selects de cidades e estados com AJAX (PHP e jQuery)” (http://www.daviferreira.com/posts/populando-selects-de-cidades-e-estados-com-ajax-php-e-jquery). No entanto para o meu caso a solu√ß√£o do Davi teria que ser reinventada tendo em vista que no meu form haviam 3 conjuntos de Estado/Cidade. Um para os dados de endere√ßo do usu√°rio e outros dois para os dados profissionais. Uma op√ß√£o seria repetir o c√≥digo 3 vezes, uma para cada conjunto, o que n√£o √© nada elegante.

A op√ß√£o foi portanto, criar uma fun√ß√£o dentro do Javascript que fizesse o trabalho sujo de forma din√Ęmica. Ao inv√©s de criar uma fun√ß√£o JS que aproveitasse o JQuery, segui a sugest√£o do Basil Godman, “Definindo suas pr√≥prias fun√ß√Ķes com o JQuery” (http://blogs.microsoft.co.il/blogs/basil/archive/2008/09/22/defining-your-own-functions-in-jquery.aspx) e criei uma fun√ß√£o do pr√≥prio JQuery.

Outra coisa que fiz tamb√©m foi retirar o campo de “span” est√°tico com a mensagem “Carregando …” como sugere o Davi. Ela agora aparece de forma din√Ęmica dentro da pr√≥pria fun√ß√£o. Facilitando a manuten√ß√£o, inclus√£o de em gif animado, uma classe espec√≠fica e despoluindo o HTML, imagina isso para 4 ou 5 campos Estado/Cidade!

Abaixo você poderá baixar o código completo inclusive com o DDL e o DML do MySQL, além de verificar os 4 arquivos necessários para que tudo funcione comentados.

Arquivos completos para download

Arquivo de conex√£o com o Banco

$con = mysql_connect( 'localhost', 'root', '' ) ;
mysql_select_db( 'cadastro', $con );

O PHP e o HTML dos Selects

<?php
require("conn.open.php");

function listaEstadosOrderIdAsc(){
	return mysql_query("SELECT cod_estados, sigla FROM estados ORDER BY sigla ASC");
}
?>
<p>
  <label for="cod_estados">Estado:</label>
  <select name="cod_estados" id="cod_estados">
    <option value="">(selecione aqui)</option>
    <?php $estados = listaEstadosOrderIdAsc(); while ($row = mysql_fetch_object($estados)) { ?>
    <option value="<?php echo $row->cod_estados; ?>"><?php echo $row->sigla; ?></option>
    <?php } ?>
  </select>
  <label for="cod_cidades">Cidade:</label>
  <select name="cod_cidades" id="cod_cidades">
    <option value="">-- Escolha um estado --</option>
  </select>
</p>

Aqui a função JQuery propriamente dita, comentada para facilitar o entendimento.

$(document).ready(function(){

	// Por Rogerio Coli, www.rcoli.com.br - favor n√£o remover
	jQuery.fn.carregaCidades = function() {
		
		// Objeto que guarda os argumentos
		var args 					= arguments[0] || {};
		
		//id do Select de Cidades
		var idSelectCidade 			= args.idSelectCidade;
		
		// P√°gina que ir√° criar o JSon
		var paginaPhpCidades		= 'cidades.ajax.php';
		
		// Conte√ļdo do elemento span que vai aparecer enquanto carregam as cidades, 
		// pode ser substituído por uma imagem. Coloque a tag completa	
		var carregandoMsg			= 'Aguarde, carregando...' 	
		
		// Classe do elemento span que vai aparecer enquanto carregam as cidades
		var carregandoClass			= 'class';
		// após as cidades carregarem aparece esta mensagem
		var jsonPrimeiroElemento 	= '(selecione a cidade)';
		// Aqui eu pego a frase do primeiro option de Cidade  
		var primeiroElemento		= $(idSelectCidade).find('option:first').html();
		
		
		if( $(this).val() ) {
			// escondendo as cidades até carregarem
			$(idSelectCidade).hide();
			// mensagem de espera: carregando
			$(idSelectCidade).after('<span class='+ carregandoClass +'>'+carregandoMsg+'</span>');
			
			$.getJSON(paginaPhpCidades+'?search=',{cod_estados: $(this).val(), ajax: 'true'}, function(j){
					// √Č importante que o value seja vazio pra que o formul√°rio n√£o seja enviado vazio
					// caso use o form validate
				var options = '<option value="">'+jsonPrimeiroElemento+'</option>';    
				for (var i = 0; i < j.length; i++) {
					// √Č importante que o value seja vazio pra que o formul√°rio n√£o seja enviado vazio
					// caso use o form validate
					options += '<option value="' + j[i].cod_cidades + '">' + j[i].nome + '</option>';
				} 
				// mostrando as cidades após carregarem e removendo a mensagem de espera
				$(idSelectCidade).html(options).show();
				$(idSelectCidade).next().remove();
			});
		} else {
			$(idSelectCidade).html('<option value="">'+primeiroElemento+'</option>');
		}
		
	};
	//Inciando o SELECT, importante ao recarregar a p√°gina
	$("#cod_estados option:first").attr('selected','selected');
	// Aqui eu chamo a função e o método que irá carregá-la
	$('#cod_estados').change(function(){ $(this).carregaCidades({idSelectCidade: '#cod_cidades'}); })
});

O Arquivo AJAX que monta o JSon

header( 'Cache-Control: no-cache' );
header( 'Content-type: application/xml; charset="utf-8"', true );

require("conn.open.php");

$cod_estados = mysql_real_escape_string( $_REQUEST['cod_estados'] );

$cidades = array();

$sql = "SELECT cod_cidades, nome
		FROM cidades
		WHERE estados_cod_estados=$cod_estados
		ORDER BY nome";
$res = mysql_query( $sql );
while ( $row = mysql_fetch_assoc( $res ) ) {
	$cidades[] = array(
		'cod_cidades'	=> $row['cod_cidades'],
		'nome'			=> htmlentities($row['nome']),
	);
}

echo( json_encode( $cidades ) );

JQuery Form Validation РValidação de Datas no Google Chrome

Recentemente me deparei com um BUG ser√≠ssimo do plugin do JQuery, form validation. O campo “data:true” do jQuery Validation Plugin 1.9.0 aceita o formato de data em portugu√™s (ex: 31/12/2011) em todos os navegadores exceto o Google Chrome (15.0.874.121 m, no momento desse artigo) e possivelmente no Safari, de acordo com algumas reclama√ß√Ķes de outros programadores com o mesmo problema.

Ao tentar buscar alternativas de contornar o problema eu percebi que havia uma funcionalidade j√° desenvolvida para a valida√ß√£o de data no formato DE (alem√£o,”29.04.1994″ ou “1.1.2006″), bastante semelhante ao padr√£o brasileiro. S√≥ que essa fun√ß√£o n√£o aparece no arquivo dispon√≠vel para o download, ou foi retirada posteriormente como pode ser visto no reposit√≥rio do GitHub do plugin. Sendo que na linha 275 (messages) alguns arquivos do site do plugin ainda fazem refer√™ncia a tal fun√ß√£o: “dateDE”.

Para normalizar a situa√ß√£o eu sugiro incluir algumas linhas de c√≥digo no seu “jquery.validate.js”, vamos a elas:

Procure nas linhas 268/275 dentro de messages aonde aparece a mensagem de data e coloque abaixo de date a linha destacada:

messages: {
	required: 	"Campo obrigat&oacute;rio.",
	remote: 	"Por favor revise este campo.",
	email:		"Por favor digite um e-mail v&aacute;lido.",
	url: 		"Por favor digite uma URL v&aacute;lida.",
	date:		"Por favor digite uma data v&aacute;lida.",
	dateISO: 	"Por favor digite uma data v&aacute;lida (ISO).",
	dateDE: 	"Por favor digite uma data v&aacute;lida (DE, BR).",
	number: 	"Por favor digite um n√ļmero v&aacute;lido.",
	digits: 	"Por favor digite somente n√ļmeros.",
	creditcard:	"Por favor digite um cartão de crédito v&aacute;lido.",
	equalTo: 	"Por favor digite o mesmo valor.",
	accept: 	"Por favor digite um valor com uma extens√£o v&aacute;lida.",
	maxlength: 	$.validator.format("Por favor digite mais de {0} caracteres."),
	minlength:	$.validator.format("Por favor digite pelo menos {0} caracteres."),
	rangelength:$.validator.format("Por favor digite um valor entre {0} e {1} caracteres."),
	range: 		$.validator.format("Por favor digite um valor entre {0} e {1}."),
	max: 		$.validator.format("Por favor digite um valor menor ou igual a {0}."),
	min: 		$.validator.format("Por favor digite um valor maior ou igual a {0}.")
},

Em seguida ache a função dateISO lá pela linha 1050 e insira a a função abaixo. Atente que há a função original e a alterada

// //http://docs.jquery.com/Plugins/Validation/Methods/dateDE
		dateDE:function(value,element){
			// Original DE
			//return this.optional(element)||/^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);
			// Oposite ISO
			return this.optional(element)||/^\d{1,2}[\/-]\d{1,2}[\/-]\d{4}$/.test(value);
		},

Agora é só fazer a chamada normalmente em sua validação:

$("#form").validate({
	rules: 
	{
		data_nascimento: { required:true, minlength: 10, dateDE:true 	},
	}
});

Atente que esta validação não verifica se é uma data válida, somente se atende a um formato específico. Para a validação de uma data válida (meses com 30 ou 31 dias, anos bissextos e etc) é necessário
extender as funcionalidades do plugin. Em breve farei isso, até lá.

Assine o RSS de meus Artigos e Comentários.