Eseguire una richiesta AJAX dopo che un'altra richiesta AJAX è terminata
Un file JS sta effettuando una chiamata ajax. All'interno del success di questa chiamata ajax viene effettuata un'altra chiamata AJAX. La seconda chiamata verifica se l'email è già stata registrata. Se è già registrata, la seconda chiamata AJAX non riceve dati di ritorno come mostrato in firebug e nella console Chrome. Tuttavia, lo stesso codice funziona correttamente in localhost mentre il problema menzionato si verifica SOLO sul server online.
La pagina ospitata si trova su http://twmobilefitness.com/signup/. Il problema si verifica quando si fa clic sul link 'Register Now' alla fine. È necessario registrarsi due volte con lo stesso indirizzo email per far verificare il problema.
JS:
$.ajax( {
url : base_url+"/wp-admin/admin-ajax.php",
type : 'GET',
cache : false,
data : 'action=check_user_name&'
+ Math.floor( ( Math.random() * 100 ) +1 )
+ '&user_name='+user_name,
success : function( result ) {
if ( parseInt( result ) == 0 ) {
$( ".result" ).html( '<span class="error">Nome utente non disponibile </span>' );
} else if ( parseInt( result ) == 1 ) {
$.ajax( {
url : base_url
+ "/wp-admin/admin-ajax.php",
type : 'GET',
cache : false,
data : 'action=check_email_used&'
+ Math.floor( ( Math.random() *100 ) +1 )
+ '&email=' + email,
success : function( result_email ) {
if ( parseInt( result_email ) == 0 ) {
$( ".result" ).html( '<span class="error">Email già utilizzata </span>' );
} else if ( parseInt( result_email ) == 1 ) {
$( ".result" ).html( '' );
$( ".signup_div" ).hide();
$( ".signup_emergency_contact" ).show();
}
}
} );
}
}
} );
functions.php contiene
add_action('wp_ajax_check_user_name','check_user_name');
add_action('wp_ajax_nopriv_check_user_name','check_user_name');
add_action( 'wp_ajax_check_email_used','check_email_used' );
add_action( 'wp_ajax_nopriv_check_email_used','check_email_used' );
function check_user_name() {
global $wpdb;
$user_name = trim( $_GET['user_name'] );
$MobTraining = new MobTraining();
$table =trim( "{$wpdb->prefix}users" );
$array_where['user_login'] = $user_name;
$sql_fetch = $MobTraining->fetch( $table, $array_where );
$row = $wpdb->get_results( $sql_fetch, ARRAY_A );
if ( sizeof( $row ) != 0 ) {
echo '0';
} else {
echo '1';
}
die();
}
function check_email_used() {
global $wpdb;
$email = trim( $_GET['email'] );
$MobTraining = new MobTraining();
$table = trim( "{$wpdb->prefix}users" );
$array_where['user_email'] = $email;
$sql_fetch = "SELECT * FROM $table WHERE `user_email`='$email'";
$row = $wpdb->get_results( $sql_fetch, ARRAY_A );
if ( sizeof( $row ) != 0 ) {
echo '0';
} else {
echo '1';
}
die();
}
Come far funzionare il codice sul server online?
Quello che stai riscontrando (AJAX funziona localmente, ma non sul server) è un problema di ritardo. Localmente tutto funziona così velocemente che non riesci a vedere il problema. In breve, questo è il tuo problema:
Callback AJAX (A) viene eseguito > Callback AJAX (B) non sa che deve aspettare (A) > Non riesci a vedere il problema nella tua installazione locale perché (A) termina troppo velocemente.
Quindi devi trovare un modo per dire al tuo Callback (B) che deve aspettare (A). Ecco come:
Registrare script e spostare dati da PHP a JS
Registra e accoda i tuoi script e localizza i dati nel modo corretto: incapsula tutto in una funzione o metodo e aggancialo a wp_enqueue_scripts (pubblico/temi), login_enqueue_scripts (password/login/registrazione) o admin_enqueue_scripts. Poi usa wp_localize_script() per spostare i dati da PHP a JS e renderli accessibili lì.
add_action( 'admin_enqueue_scripts', 'wpse118772jsObject' );
function wpse118772jsObject()
{
$scriptHandle = 'custom-script-name';
// Dovrebbe essere diviso in funzioni o metodi separati
wp_register_script(
$scriptHandle,
plugins_url( __FILE__, 'your/path' ),
array( 'jquery' ),
plugin_dir_path( __FILE__ ).'your/path' ),
true
);
wp_enqueue_script( $scriptHandle );
wp_localize_script(
$scriptHandle,
'pluginObject',
array(
'ajaxURl' => admin_url( 'admin_ajax.php' ),
'custom' => array(
// dati personalizzati qui
),
),
);
}
Come usare jQuery AJAX nel modo corretto
Ci sono diverse funzioni che puoi usare: la funzione predefinita $.ajax({}); o le sue scorciatoie $.post();, $.getJSON();, ecc.
Quindi puoi semplicemente usare qualcosa come il seguente - utilizzando i metodi dell'oggetto success/fail.
( function( $, plugin ) {
"use strict";
$.ajax( {
url : plugin.ajaxURl,
data : {
// altri dati
},
// Assumiamo che tu risponda con un wp_send_json_success/error() corretto nel callback PHP.
dataType : "json",
// Trasformazione della richiesta possibile qui.
beforeSend : function( xhr ) {
// Esempio:
// xhr.overrideMimeType( 'application/json' );
},
// I gestori effettivi
success : function( data, textStatus, jqXHR ) {
// Gestisci la trasformazione dei dati o la manipolazione del DOM qui.
},
error : function( jqXHR, textStatus, errorThrown ) {
// silenzioso: Registra l'errore
console.info( errorThrown );
// rumoroso: Lancia un'eccezione
throw errorThrown;
}
} );
} )( jQuery, pluginObject || {} );
Se vuoi andare più in profondità e fare le cose davvero nel modo giusto, dovrai usare il method chaining. (C'è ancora spazio per miglioramenti).
( function( $, plugin ) {
"use strict";
$.ajax( {
url : plugin.ajaxURl,
data : {
// altri dati
},
} )
.done( function( data ) {
// Gestisce solo risposte di successo
} )
.fail( function( reason ) {
// Gestisce solo errori
console.debug( reason );
} )
.always( function( data, textStatus, response ) {
// Se vuoi separare manualmente le cose
// response diventa errorThrown/reason OPPURE jqXHR in caso di successo
} )
.then( function( data, textStatus, response ) {
// Se lavori con una deferred.promise, usa questo metodo
// Di nuovo, dovrai separare manualmente successo/errore
} );
} )( jQuery, pluginObject || {} );
Nota: Per esempi migliori del wrapper attorno al callback, dai un'occhiata a commonjs o AMD e alle loro differenze.
Aspettare altre risposte AJAX
La parte interessante - e più potente - di tutta la gestione AJAX di jQuery (e altre librerie) è come aspettare che A sia terminato per poi avviare B e la sua elaborazione. La risposta è il caricamento "deferred" e le "promises".
Aggiungerò un esempio veloce. Dovresti forse pensare di costruire un oggetto e separare le cose aggiungendole via this. all'oggetto, ma per un esempio il seguente dovrebbe essere sufficiente:
Esempio (A) Questo è fondamentalmente come lo faccio io. Dovrai riempire i pezzi da solo.
( function( $, plugin ) {
"use strict";
$.when(
$.ajax( {
url : pluginURl,
data : { /* ... */ }
} )
.done( function( data ) {
// 2a chiamata terminata
} )
.fail( function( reason ) {
console.info( reason );
} )
)
// Di nuovo, potresti usare .done(). Vedi la documentazione di jQuery.
.then(
// Successo
function( response ) {
// È andato a buon fine
// In caso di più richieste, entrambe devono avere successo
},
// Fallimento
function( resons ) {
// Ha generato un errore
// in caso di errori multipli, lancia il primo
},
);
} )( jQuery, pluginObject || {} );
Esempio (B) Non l'ho mai provato così, ma dovrebbe funzionare comunque. Più facile da leggere, ma preferisco le promesse risolte con $.when().
( function( $, plugin ) {
"use strict";
$.ajax( {
url : plugin.ajaxURl,
data : {
// altri dati
}
} )
.done( function( data ) {
// Gestisce solo risposte di successo
} )
.fail( function( reason ) {
console.info( reason );
} )
// Promise terminata:
.then( function( data ) {
$.ajax( {
url : pluginURl,
data : { /* ... */ }
} )
.done( function( data ) {
// 2a chiamata terminata
} )
.fail( function( reason ) {
console.info( reason );
} );
} );
} )( jQuery, pluginObject || {} );
Se vuoi approfondire ancora di più, leggi la documentazione su deferred e then.
async/ await
MODIFICA Poiché questa risposta riceve molta attenzione nel corso degli anni e ha già 8 anni, dai un'occhiata al seguente snippet.
Tieni presente che async/await lavora ancora con le Promises. È solo zucchero sintattico. Tieni anche presente a cosa si riferisce this quando usi funzioni abbreviate come visto in handlerB().
Questo funzionerà anche con jQuery.
( function( $, plugin ) {
const handlerA = async function( plugin ) {
try {
let res = await $.ajax( {
url : plugin.ajaxURl,
data : { /* alcuni dati */ }
} )
.done( function( data ) {
// Gestisce solo risposte di successo
} )
.fail( function( reason ) {
console.error( reason );
} )
return res;
} catch ( err ) {
console.error( err )
}
}
const handlerB = async data => { /* un'altra richiesta AJAX */ }
// Esegui
// …aspetta…
let $resultA = await handlerA( plugin )
// Ora esegui B
let $resultB = await handlerB( $resultA )
// Fai qualcosa con $resultB
} )( jQuery, pluginObject || {} );
In realtà non sto utilizzando alcun plugin. Una semplice chiamata AJAX di WordPress. Per quanto riguarda il problema del ritardo del server - Firebug mostra che la richiesta AJAX è completata senza dati ricevuti. Lasciami analizzare la tua risposta più in dettaglio.
Istiaque Ahmed
@IstiaqueAhmed La descrizione sopra non è pensata per essere un plugin. Solo la base per scrivere il tuo plugin (o, nel caso in cui non ti interessi la separazione delle responsabilità, il tuo tema).
kaiser
Grazie, questo è stato di grande aiuto in un progetto recente. Ho già votato positivamente molto tempo fa ;-) Volevo anche solo menzionare che le callback success, error, complete sono ora deprecate a favore delle promise callback menzionate nella risposta.
birgire
@birgire Per favore [modifica] la risposta. Ho verificato e solo la prima parte è ora deprecata. Grazie in anticipo e grazie per le gentili parole :)
kaiser
@kaiser negli esempi 'In attesa di altre risposte AJAX' A e B, dove si trovano esattamente le seconde chiamate ajax? Non riesco a vedere una seconda chiamata ajax nell'Esempio A.
HappyCoding
Per eseguire una richiesta AJAX dopo il completamento di un'altra richiesta AJAX, devi aggiungere la seguente riga:
async: false,
Ovvero, devi aggiungere async: false nel metodo ajax come mostrato di seguito:
$.ajax( {
url : base_url+"/wp-admin/admin-ajax.php",
type : 'GET',
async: false,