JavaScript $.each と for(...in...)の並び順について
仕事用備忘録。
JavaScriptの$.each文とfor(...in...)文の並び順について
少し躓いたため、メモメモ。。
現象
ある案件の選択ボックスの中身がコード順に並ばない。
選択ボックスの中身は連想配列で複数組入っている。
簡単にいうと
名称(コード番号)
・
・
を表示するボックス内で小さい数字から順に並んでほしいのだが、
名称(1120)
名称(4569)
名称(0110)
のように
「なぜか0始まりのコードだけ後ろに回される」という現象。
0始まりだけ後ろに存在する以外は、
コード順に並んでいる。
ちなみにこのデータはSQLで引っ張ってきており、
SQLではきちんと小さい数字順に並んでいる。
ソースコード
JavaScriptソース
// aボタンが押された時
$('.button_a').on('click', function(){
$('.button_a').removeClass('isActive');
$('.button_b').removeClass('isActive');
// aとbのリストのオプションを消す
$('.a_list option').remove();
$('.b_list option').remove();
// aとbのリストの最初(配列でいうと[0])に「選択してください。」の文言追加
$('.a_list').append($('<option>').text('選択してください。').attr('value', 0));
$('.b_list').append($('<option>').text('選択してください。').attr('value', 0));
$(this).toggleClass('isActive');
//ajaxでデータ取得(オプションは割愛)
$.ajax({
url: '<?php echo Router::url(array('controller' => '', 'action' => ''));?>',
type: "GET",
data:{
"" : $(this).val()
},
cache: false,
async: false,
dataType: 'json',
//成功したら
success: function(data){
//「選択してください。」の分、件数を1個マイナス ⇒ 後で件数を使用
a_count = -1;
//each文で繰り返し処理
$.each(data, function(id, name){
//disp_nameという変数に名称を代入
disp_name = name;
//idが0より大きいなら(すべて)リスト内に「名称(id)」という文言を格納する
//ついでにid値をvalue属性に付加しておく
if (id > 0) {
disp_name = disp_name + '(' + id + ')';
}
$('.a_list').append($('<option>').text(disp_name).attr('value', id));
a_count++;
});
}
//aのリストの上に隠していたメッセージエリアを可視化する ⇒ ここで件数を使用
$('#a_message_area').show();
$('#a_message_area').text(a_count + '件が見つかりました。');
},
// データ格納に失敗したらエラーページへ
error: function(){
location.href='<?php echo Router::url(array('controller' => '', 'action' => 'error'));?>';
}
});
});
コードの内容が分かりづらいかもしれないが、
aのリストを構成するのがこの内容ということである。
isActiveはよくわからないが、多分いるのでおいとく。
bのリストも同じ感じで下にある。
今回はeachの繰り返し処理の並びがおかしいという話なので割愛。
原因
JavaScript each で検索かけたところ、
並び順を保証しないメソッドであるとのこと。
保証していないというより、あまり柔軟な決め事ができない?
既にeachの中で決まっている並びがあるんだと感じた。
数字は1.2.3......9.0の並びとか?かな。
ようわからんけども。
対策1.if文で並びを変えてみる
単純にeach文をif条件分岐で2つ用意して、
idが低い方から並ぶのでは?という予想。
変更後コード
success: function(data){
a_count = -1;
$.each(data, function(id, name){
disp_name = name;
//★ここから変更★
if (id > 0
&& id < 1000) {
disp_name = disp_name + '(' + id + ')';
$('.a_list').append($('<option>').text(disp_name).attr('value', id));
a_count++;
}else if( id >= 1000){
disp_name = disp_name + '(' + id + ')';
$('.a_list').append($('<option>').text(disp_name).attr('value', id));
a_count++;
});
}
//★ここまで★
$('#a_message_area').show();
$('#a_message_area').text(a_count + '件が見つかりました。');
},
error: function(){
location.href='<?php echo Router::url(array('controller' => '', 'action' => 'error'));?>';
}
});
});
結論 ⇒ 無意味。
変わらない。
並び順変わらない。
対策2.for(...in...)文で並びを変えてみる
最終的なコードがこちら
success: function(data){
//★ここから変更★
for(var id in data){
if(id > 0 && id < 1000){
disp_name = data[id] + '(' + id + ')';
$('.a_list').append($('<option>').text(disp_name).attr('value', id));
}
}
for(var id in data){
if(id >= 1000){
disp_name = data[id] + '(' + id + ')';
$('.a_list').append($('<option>').text(disp_name).attr('value', id));
}
}
$('#bank_message_area').show();
$('#bank_message_area').text((Object.keys(data).length - 1 ) + '件が見つかりました。');
},
//★ここまで★
結論 ⇒ OK
並び順は希望通り、小さい数字順に変わった。
コード的に何が変わったかというと、
・each ⇒ for
・name ⇒ data[id] (ここだけ最初、表記の仕方が分からなかった)
・a_count++; ⇒ 無し
・a_count ⇒ Object.keys(data).length
くらい。
countは連想配列に使えないため、Object.keys().lengthに変更して
件数を取得した。
ちなみに、こちらでも条件分岐している意味はあるかというと、ある。
for(...in...)でも最初のコードのように
for(var id in data){
if(id > 0 ){
disp_name = data[id] + '(' + id + ')';
$('.a_list').append($('<option>').text(disp_name).attr('value', id));
}
}
だけだと、数字は小さい順には並ばない。
まとめ
each文もfor(...in...)文も並び順は一緒。
JavaScriptの仕様なのかな?
JavaScriptはほとんど使わないからわかりません。
調べる気にもなりません。
ただ、for(...in...)文を条件分岐してみると、
並びは変えてくれた。
each文は分岐させても一緒だった。
つまり、総合的に統合した段階で判別している?
並びを決めるコードを実際に実行する段階の違いという結論。
繰り返し処理 ⇒ データ格納 ⇒ その他 ⇒ 画面表示
↑forはここ ↑eachはここ
ひとまず、そうゆうことにしとこう。
この記事が気に入ったらサポートをしてみませんか?