ある日の業務で、__aタグが押下されてページ遷移する時にAjaxでデータベースと情報のやり取りをさせたいなあ__と思い、
jQueryをザーと書いたのですが、『ん?ページ遷移直後のページではデータが更新されてないのに、ページ更新したり他のページに移動するとデータが直ってるんだが?』となり30分ほど沼にはまることとなりました。
調べてみたんですが、Ajaxって実行の順番が保証されていないんですね。
なので自分の場合も、バックエンドの処理をajaxで実行して、それが完了する前にページ遷移が行われてしまったので、直後のページではデータが更新されない、という結果になっていたようです。
なので、この記事では__ajaxで行われる動作をキチンとコントロールしたい!__という時に使える方法をいくつかまとめてみましたので、是非とも参考になりましたら幸いです!
元々のコード(ダメパターン)
$(function(){
$(document).on('click', 'a', function() {
$.ajax({
url: '/app/do_something/',
type: 'GET',
dataType: 'json',
cache: false,
async: true,
data: {
"var1":"hello",
"var2":"world"
}
})
.done(function(data){
const errorMessage = Object.values(data)
if (errorMessage[0] !== null) {
alert(errorMessage[0]);
}
})
.fail(function(XMLHttpRequest, textStatus, errorThrown){
alert('errorです');
});
});
});
まずはうまく動作しなかった場合のコードを貼っておきます。
期待していた動きは下記の様な流れです。
- ユーザがaタグをクリック
- ページ遷移が行われる前にAjaxでデータベースと通信して情報を更新
- ajaxで行った処理が完了したら、遷移先のページにユーザを飛ばす
- 更新されたデータが画面に描画される
ただ、上記の書き方だと、aタグでの遷移がAjaxの処理が終わるよりも前に行われてしまったので、
Ajaxでの処理を完了してからページ遷移してもらうように書き換える必要があります。
#対処法1(その場での解決方法)
$(function(){
$(document).on('click', 'a', function(e) {
e.preventDefault();
targetUrl = $('a').attr('href');
// 追加
$.ajax({
url: '/app/do_something/',
type: 'GET',
dataType: 'json',
cache: false,
async: true,
data: {
"var1":"hello",
"var2":"world"
}
})
.done(function(data){
const errorMessage = Object.values(data)
if (errorMessage[0] !== null) {
alert(errorMessage[0]);
}
})
.fail(function(XMLHttpRequest, textStatus, errorThrown){
alert('errorです');
});
window.location = targetUrl;
// 追加
});
});
対処法その1がこちらです。
まずはaタグがクリックされたタイミングで、aタグ本来の機能をストップ(preventDefault())させます。
その次の行で遷移先のURLを変数に入れて、最後にAjaxの処理の後のところで「window.location」を使ってページ遷移を行っています。
なお、「window.location」は、.done()の中の「if (errorMessage[0] !== null)」のあとに書いても良いのですが、
実際の業務では返ってきた情報を基にifで分岐したりして処理を行う必要があり、
__「Ajaxの中で複雑な処理は書かないで、あくまでデータを取ってくるだけの処理に絞りたい」__との先輩のアドバイスからAjaxの外に持ってきました。
というわけでこの書き方で動きはしましたが、
「もうちょい賢いやり方ありそうだなあ」と思い家に帰って調べたところ2つほどスマートそうなものがありましたので。こちらも書いておきます。
#対処法2(ajaxStop)
$(function(){
$(document).on('click', 'a', function(e) {
e.preventDefault();
targetUrl = $('a').attr('href');
// 追加
$.ajax({
url: '/app/do_something/',
type: 'GET',
dataType: 'json',
cache: false,
async: true,
data: {
"var1":"hello",
"var2":"world"
}
})
.done(function(data){
const errorMessage = Object.values(data)
if (errorMessage[0] !== null) {
alert(errorMessage[0]);
}
})
.fail(function(XMLHttpRequest, textStatus, errorThrown){
alert('errorです');
});
$(document).ajaxStop(function() {
window.location = targetUrl;
});
// 追加
});
});
見た瞬間「自分が書いたコードよりも明示的でイケてるなあ」と思いました笑
「.ajaxStop」は文字通りAjaxの処理が終わったタイミングで勝手に動作してくれるようです。
「Ajaxが止まったら中の処理をやるよ!」なのか「Ajaxを止めるよ!」なのかやや紛らわしさはありますが使えそうです。
#対処法3(When/Done)
$(function(){
$(document).on('click', 'a', function(e) {
e.preventDefault();
targetUrl = $('a').attr('href');
// 追加
$.when(
// 追加
$.ajax({
url: '/app/do_something/',
type: 'GET',
dataType: 'json',
cache: false,
async: true,
data: {
"var1":"hello",
"var2":"world"
}
})
.done(function(data){
const errorMessage = Object.values(data)
if (errorMessage[0] !== null) {
alert(errorMessage[0]);
}
})
.fail(function(XMLHttpRequest, textStatus, errorThrown){
alert('errorです');
})
)
.done( function() {
window.location = targetUrl;
});
// 追加
});
});
こちらの場合だと、【対処法2】と比べてAjaxの処理を「$.when」で囲む必要があり、一見やや手間がかかりそうですが、
__複数のAjax処理を行うことができる__のが強みです。
くわしくはこちらのブログにて取り上げられておりますので、詳しく知りたい方はご覧いただけるとよいかと思います。
まとめ
今回はAjaxでの処理を順序を切って進めるための書き方をいくつかまとめました。
同じことをやろうと思っても、いろんな方法があるのはプログラミングの楽しいところですね笑
また、この記事への感想や内容への指摘など、お気軽にコメントを頂けますと幸いです!
最後までご拝読ありがとうございました!