Javascript e AJAX, só funciona quando usando alert ()
-
13-09-2019 - |
Pergunta
Estou tendo problemas com meu javascript. Parece estar agindo estranhamente. Isto é o que está acontecendo. Eu tenho um formulário, após os submete usuário, ele chama uma função (evento onsubmit) para verificar os dados apresentados, se algo de ruim ou se o nome de usuário / e-mail já está em banco de dados (usando ajax para esta parte) ele vai retornar falso e erros de exibição usando DOM. Aqui está o código abaixo. O que é estranho sobre isso, é que ele só funciona quando eu uso um alerta vazia ( '') mensagem, sem ela, ele simplesmente não funciona. Obrigado pela ajuda.
//////////////////////////////////////
function httpRequest() {
var xmlhttp;
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else if (window.ActiveXObject) {
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
} else {
alert("Your browser does not support XMLHTTP!");
}
return xmlhttp;
}
function validateRegForm(reg) {
var isValidForm = true;
var warningIcon = "";//for later in case we want to use an icon next to warning msg
with(reg) {
var regFormDiv = document.getElementById("registration_form");
//Check if dynamic div exist, if so, remove it
if(document.getElementById('disp_errors') != null) {
var dispErrorsDiv = document.getElementById('disp_errors');
document.getElementById('reg_form').removeChild(dispErrorsDiv);
}
//Dynamically create new 'div'
var errorDiv = document.createElement('div');
errorDiv.setAttribute('id','disp_errors');
errorDiv.setAttribute('style','background-color:pink;border:1px solid red;color:red;padding:10px;');
document.getElementById('reg_form').insertBefore(errorDiv,regFormDiv);
var xmlhttp = httpRequest();
var available = new Array();
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState == 4)
{
var response = xmlhttp.responseText;
if(response != "") {
//Return values
var newValue = response.split("|");
available[0] = newValue[0];
available[1] = newValue[1];
}
}
}
xmlhttp.open("GET","profile_fetch_reg_info.php?do=available&un="+u_username.value+"&email="+u_email.value+"",true);
xmlhttp.send(null);
alert(' '); ////////////WITHOUT THIS, IT DOESN'T WORK. Why?
if(available[1] == "taken") {
errorDiv.innerHTML += warningIcon+'Username is already taken!<br />';
isValidForm = false;
} else if(u_username.value.length < 4){
errorDiv.innerHTML += warningIcon+'Username must be more than 4 characters long!<br />';
isValidForm = false;
} else if(u_username.value.length > 35) {
errorDiv.innerHTML += warningIcon+'Username must be less than 34 characters long!<br />';
isValidForm = false;
}
if(available[0] == "taken") {
errorDiv.innerHTML += warningIcon+'Email address entered is already in use!<br />';
isValidForm = false;
} else if(u_email.value == ""){
errorDiv.innerHTML += warningIcon+'Email address is required!<br />';
isValidForm = false;
} else {
//Determine if email entered is valid
var filter = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if (!filter.test(u_email.value)) {
errorDiv.innerHTML += warningIcon+'Email entered is invalid!<br />';
u_email.value = "";
isValidForm = false;
}
}
if(u_fname.value == ""){
errorDiv.innerHTML = warningIcon+'Your first name is required!<br />';
isValidForm = false;
}
if(u_lname.value == ""){
errorDiv.innerHTML += warningIcon+'Your last name is required!<br />';
isValidForm = false;
}
if(u_password.value.length < 4){
errorDiv.innerHTML += warningIcon+'Password must be more than 4 characters long!<br />';
isValidForm = false;
} else if(u_password.value.length > 35) {
errorDiv.innerHTML += warningIcon+'Password must be less than 34 characters long!<br />';
isValidForm = false;
} else if (u_password.value != u_password2.value) {
errorDiv.innerHTML += warningIcon+'Password and re-typed password don\'t match!<br />';
isValidForm = false;
}
if(u_squestion.value == ""){
errorDiv.innerHTML += warningIcon+'A security question is required!<br />';
isValidForm = false;
}
if(u_sanswer.value == ""){
errorDiv.innerHTML += warningIcon+'A security answer is required!<br />';
isValidForm = false;
}
if(u_address.value == ""){
errorDiv.innerHTML += warningIcon+'Address is required!<br />';
isValidForm = false;
}
if(u_city.value == ""){
errorDiv.innerHTML += warningIcon+'City is required!<br />';
isValidForm = false;
}
if(u_state.value == ""){
errorDiv.innerHTML += warningIcon+'State is required!<br />';
isValidForm = false;
}
if(u_zip.value == ""){
errorDiv.innerHTML += warningIcon+'Zip code is required!<br />';
isValidForm = false;
}
if(u_phone.value == ""){
errorDiv.innerHTML += warningIcon+'Phone number is required!<br />';
isValidForm = false;
}
if(isValidForm == false)
window.scroll(0,0);
return isValidForm;
}
}
Solução
O alert()
ajuda porque que os atrasos de processamento do javascript permanecendo nessa função (tudo, desde o alert()
até o fundo), deixando tempo suficiente para o pedido de AJAX para ser concluído. A primeira letra em AJAX significa "assíncrona" o que significa que (por padrão) a resposta virá em "algum momento no futuro", mas não imediatamente.
Uma correção (que você deve não implementar) é fazer com que o síncrono processamento (alterando o terceiro argumento de open()
ser false
) que vai parar o processamento do seu script (e toda a página web ), até a solicitação retorna. Isso é ruim porque vai efetivamente congelar o navegador até que os concluída solicitação.
A correção adequada é para reestruturar seu código para que qualquer tratamento que depende do resultado da solicitação AJAX vai para a função onreadystatechange
, e não pode ser na função principal que inicia o pedido de AJAX.
A forma como este é geralmente tratado é modificar o DOM (antes do pedido de AJAX é enviada) para tornar o formulário somente leitura e exibir algum tipo de mensagem "processamento", em seguida, no manipulador de resposta AJAX, se está tudo ok (o servidor respondeu adequadamente e validação foi bem sucedida) submit()
chamada no formulário, caso contrário, tornar o formulário wriable novamente e exibir quaisquer erros de validação.
Outras dicas
O problema é que XMLHTTPRequest é assíncrona -. Ele envia a solicitação em segundo plano e não esperar que ela termine
A declaração alert
faz com que o código de esperar até que o usuário clica em OK, durante a qual o pedido acabamentos.
Você precisa usar o evento onreadystatechange
, como este:
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState==4) {
// Do things
}
};
O método de atribuir a esta propriedade será chamado após a resposta é recebida. (E em outros momentos, que é por isso que você precisa verificar se readyState
é 4)
Você está enviando o pedido de forma assíncrona , por causa disso:
xmlhttp.open(..., true);
Passando true
como o terceiro argumento a meios open()
que o código continuará a ser executado antes do resultado vem de volta.
O alert()
está dando esse tempo solicitação assíncrona para concluir antes de os subseqüentes código é executado.
Eu normalmente recomendo que se deslocam todo o código que depende do resultado da chamada AJAX para o retorno de chamada, dentro de:
if(xmlhttp.readyState == 4)
bloco, mas no seu caso é necessário o resultado da chamada para saber o que retornar de sua função de validação. Nesse caso, você vai ter que usar uma chamada síncrona, passando false
para open()
. Em seguida, seu código subseqüente não será executado até que a resposta veio de volta.
Esses caras estão certos, mas eu também não se esqueça de devolver o bool do método de validação para que o envio do formulário é cancelado se o formulário não é válido.
Algo ao longo das linhas de:
<form onsubmit="return IsValid();">
...
</form>
Você também pode sempre retornar falso de validateRegForm e ter o xmlhttp.onreadystatechange = function () enviar o formulário se ele é válido, ou de outra forma exibir sua mensagem de erro.
Isso é porque a sua chamada AJAX é assíncrona. A seguir xmlhttp.send()
código é executado imediatamente. Não esperar por sua chamada ajax ao fim (a menos que você colocar o alerta).
Mover todo o código a ser executado após a chamada ajax para o método de retorno para garantir que ele é executado depois de terminar a chamada.
[Edit]:. Para além do problema, eu acho que usando AJAX apenas para validar o formulário e, em seguida, permitindo que o usuário envie a maneira usual parece um pouco estranho para mim
Você pode dividir a validação em 2 partes? Um que pode ser feito puramente no lado do cliente e outra que envolve a validação do lado do servidor. Você pode fazer a segunda parte completamente no lado do servidor após enviar e retornar os erros de volta ao cliente.
Outra opção é evitar o tradicional submeter completamente. Desde que você está fazendo a chamada ajax de qualquer maneira, por que não fazer o save / editar / whatever no próprio chamada ajax eliminando a necessidade de um envio? Tenha em mente, porém, você ainda vai precisar para apoiar o regulares enviar se o usuário tem o javascript desabilitado.
Você tem que passar o terceiro parâmetro para xmlhttp.open () como falso, então ele vai funcionar bem
Eu estava tendo o mesmo problema quando eu estava usando o type = "submit", por exemplo:
<button type="submit" class="btn btn-default" name="btn-login" id="btn-login" onclick="submitForm()">
<span class="glyphicon glyphicon-log-in"></span> Sign In
mas eu mudá-lo a type = "button" e ele funciona.
Eu tive o mesmo problema. Uma vez que eu remover o alert("")
ele não funciona. Eu percebi isso e que é o negócio.
Em HTML, quando você usa <button></button>
para colocar o botão, o navegador age de forma diferente; quando você clicar nele, depois de chamar o manipulador de eventos, ele recarrega a página e é por isso que você deve colocar um alert("")
apenas após o seu código para impedir que a página recarregar.
Você pode simplesmente usar <input type="button" value="something">
vez de <button></button>
para evitar que o navegador recarregar a página.
Eu tive o mesmo problema e simplesmente acrescentou:
<?php
usleep(200000)// 2 seconds
?>
após o javascript (que btw, implicou o adiamento jQuery 1.9.1 para a cabeça