sortable()で変更した並び順を取得するサンプル


手軽にドラック&ドロップで並び替えが実装できるJqueryUIのsortable()

並び替え後をトリガーにしてイベントを実行するプロパティはupdateかstop

並び替え後の順番を取得するにはtoArrayを使います

toArrayは並び替えられた要素のidが配列となって返ってきますので、そのままDBへの保存などに使えますね

html
<ul id="datas">
  <li id="1">1</li>
  <li id="2">2</li>
  <li id="3">3</li>
  <li id="4">4</li>
  <li id="5">5</li>
  <li id="6">6</li>
</ul>
<p id="log"></p>

js
$('#datas').sortable({
  update: function(){
      var log = $(this).sortable("toArray");
      $("#log").text(log);
  }
});

See the Pen sortable() toArray sample by yochans (@yochans) on CodePen.




頂いたコメントへの返信分です

>>リストのデータをデータベースからwhile文でループではき出した場合、各行にidを設定するにはどうしたらよいのでしょうか?
データベースからとの事なのでループ処理はphpと想定します
idが連番で良いのでしたら
num = 0;
while(num < 2){

$li = $li.'<li id="'.$num.'"></li>';

num++;
}
>>getElementById()を使って、$idを代入できるようにすればよいのでしょうか。
指定したい要素にidやclassがない要素の状態からidを代入するには、親要素を取得して子要素にアクセスする必要があります
<ul id="datas">
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>
例えばこの場合、「datas」の子要素を取得すれば子要素にIdを振り分ける事が可能です

sortable()で取得して並び順をデータベースに保存

otさんより頂いたコメントへの返信分です

phpとMysqlという事で、whileはMysqlのデータを吐き出す時のものですね
ならばnumは不要なので忘れて下さい

サンプルページができました(2018年2月6日20時25分)以降更新しながら説明を追記していきます

https://samples.repop.jp/sample/sortable.php


$dat[id]などで($datかどうかはわかりませんが)リストのHTML作成はデータIDを利用してリストにIDを振って行けば良いと思います

データベースのidは固定にしておいた方が良いので並び順用のテーブル(sort)を作成しました

簡単な流れとしましては

  1. データベースからテーブル「sort」の昇順でデータを取得してリストを作成
  2. sortable()で並べ替えたリストのデータを取得
  3. 取得したデータを$.postでデータベース編集用にphpに投げる

になるかと思います

サンプルのデータベーステーブル


id(キー)とsort(int)だけです
sortを追加する場合、初期値は空で良いと思います

リスト表示用のphp部分

//DB接続
$mysqli = new mysqli('xxxx', 'xxx', 'xxx;, 'xxx');
if ($mysqli->connect_error) {error_log($mysqli->connect_error);exit;}
$mysqli->set_charset("utf8");

//クエリ
$str_sql = "select * from `sortable` ORDER BY `sort`";
$res = $mysqli->query($str_sql);
if (!$res) {error_log($mysqli->error);exit;}

while($dat = $res->fetch_assoc()){
  $list = $list.'<li id='.$dat[id].'>'.$dat[id].'</li>';
}

//DB切断
mysqli_close($mysqli);

こちら$datで書いてますが、お好みです
whileの中身、データのidをliのidに付けてます
$list = $list.'<li id='.$dat[id].'>'.$dat[id].'</li>';

HTML

<html><head><title>sortableサンプル</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<style type="text/css">
<!--
li{
 width:100px;
 margin: 5px;
 padding: 5px;
 background: #FFF;
 border: solid 1px #000;
 list-style:none;
}
-->
</style>
<head><body>
<ul id="datas"><? echo $list ?></ul>
<p id="log"></p>
<script>
$('#datas').sortable({
        update: function(){
$.post("post.php",{sort: $(this).sortable("toArray")},
  function(data){
 $("#log").append('<p>' + data + '</p>');
  });
 }
});
</script>
</body></html>

liをulでくくってHTMLに出力しています

HTMLのうちのJavaScript部分

$('#datas').sortable({
        update: function(){
$.post("post.php",{sort: $(this).sortable("toArray")},
  function(data){
 $("#log").append('' + data + '
');
  });
 }
});


update: function()は入れ替え操作をした時に呼び出されます
$.postはajaxでphpにアクセスする際の短縮されたJqeryコードです
$(this).sortable("toArray")は配列になっているのでそのままPOST送信できます



$.post("送信先",{キー: 値},
  function(data){
 //結果を取得して処理する部分(この場合dataにphpの実行結果が入ります)
  }
  );

post.php(受け取り側のphp)
$sort = $_POST['sort'];
if($sort){
$mysqli = new mysqli('xxxx', 'xxx', 'xxx;, 'xxx');
  if ($mysqli->connect_error) {error_log($mysqli->connect_error);exit;}
  $mysqli->set_charset("utf8");

  foreach ($sort as $num => $id) {
  $str_sql = "UPDATE sortable SET sort = '$num' WHERE id = '$id'";
  $res = $mysqli->query($str_sql);
  if (!$res) {exit('データベースの更新に失敗しました');}
  $log = $log.'ID:'.$id.' SORT:'.$num.'<br />';
  }

   die('データベースに保存しました<br />'.$log);
   }

メモ

sortable()で並び順を取得したデータはid順のままなら[1,2,3,4,5]
先頭のID:1を最後に持って行った場合は[2,3,4,5,1]となります

受信した結果配列をforeachで回す時、keyとvalueは一般的な感覚とは逆で
valueがid、keyがソート順になります

データIDが1から始まっていても表示順は0からになります
違和感がある場合はデータベースに保存する時に+1すればいいかもです

サンプルコード

※上記ではpost.phpと記述していますがサンプルでは送信先用のコードも同じファイルに書いてありますがそのままでOKです
ちょっと記述汚くて申し訳ありません
データベース接続などは環境に合わせてください
<?php
////////////////////////////////////////sort変更が送信された時の処理
   $sort = $_POST['sort'];
   if($sort){
  //DB接続
  $mysqli = new mysqli('xxx', 'xxx', 'xxx', 'xxx');
  if ($mysqli->connect_error) {error_log($mysqli->connect_error);exit;}
  $mysqli->set_charset("utf8");

  foreach ($sort as $num => $id) {
  $str_sql = "UPDATE sortable SET sort = '$num' WHERE id = '$id'";
  $res = $mysqli->query($str_sql);
  if (!$res) {exit('データベースの更新に失敗しました');}
  $log = $log.'ID:'.$id.' SORT:'.$num.'<br />';
  }

   die('データベースに保存しました<br />'.$log);
   }
//////////////////////////////////////////////////////////



////////////////////////////////////////////////////表示用
//DB接続
   $mysqli = new mysqli('xxx', 'xxx', 'xxx', 'xxx');
   if ($mysqli->connect_error) {error_log($mysqli->connect_error);exit;}
   $mysqli->set_charset("utf8");

   $str_sql = "select * from `sortable` ORDER BY `sort`";
   $res = $mysqli->query($str_sql);
   if (!$res) {error_log($mysqli->error);exit;}

//接続
   while($dat = $res->fetch_assoc()){
   $list = $list.'<li id='.$dat[id].'>'.$dat[id].'</li>';
   }

//DB切断
   mysqli_close($mysqli);
//////////////////////////////////////////////////////////

?>

<html><head><title>sortableサンプル</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<style type="text/css">
<!--
li{
 width:100px;
 margin: 5px;
 padding: 5px;
 background: #FFF;
 border: solid 1px #000;
 list-style:none;
}
-->
</style>
<head><body>
<ul id="datas"><? echo $list ?></ul>
<p id="log"></p>
<script>
$('#datas').sortable({
        update: function(){
          console.log($(this).sortable("toArray"));
$.post("sortable.php",{sort: $(this).sortable("toArray")},
  function(data){
 $("#log").append('<p>' + data + '</p>');
  });
 }
});
</script>
</body></html>

22 件のコメント :

  1. はじめまして。勉強を始めたばかりの初心者でとんちんかんな質問かもしれませんが、例えば、リストのデータをデータベースからwhile文でループではき出した場合、各行にidを設定するにはどうしたらよいのでしょうか?
    ネットで検索すると、
    li id="$id"と、データベースのidを指定しています。
    試してみたのですが、うまくできませんでした。

    getElementById()を使って、$idを代入できるようにすればよいのでしょうか。
    お手数ですが、ご教示いただければ幸甚です。
    よろしくお願いいたします。

    返信削除
    返信
    1. コメントありがとうございます
      リストにidを設定する方法との事でおそらくphp処理と思い、簡単な方法を記事下部に追記させて頂きました

      見当違いの返信かもしれませんのでご了承ください
      また宜しくお願い致します

      削除
    2. 超よーちゃん様
      otと申します。
      お忙しい中、ご教示いただき、ありがとうございます。
      ここ数ヶ月、書籍やweb等で調べても理解できず、もう諦めようかと思っていたのですが、どうしても完成させたくて思い切って質問させていただきました。
      本当にありがとうございます。感謝です!!

      さて、説明不足で申し訳ありませんでした。当方、PHP、Mysqlを使用しております。
      ご教示いただいた内容を早速試しました。

      【親要素を取得して子要素にアクセスする必要があります】とのことですが、
      body内にscriptで囲み、
      var list = document.getElementById("datas");
      を記述しましたが、これでよろしいのでしょうか。
      この記述の後に、またscriptで囲み、
      num = 0;
      while(num < 2){

      $li = $li.'「li id="'.$num.'"」「/li」';

      num++;
      を記述しました。(タグが使えないので代替してます)
      コンソールで確認すると、
      $li = $li.'「li id="'.$num.'"」「/li」';の行に、SyntaxError: missing name after . operatorが出てしまいました。リストのid番号も振られていませんでした。
      記述する場所が間違っていますでしょうか。

      上記の解決策を調べつつ、図々しくその先の質問をしてもよろしいでしょうか。

      【sortable()で変更した並び順をDBへ保存】したいと思っています。
      DBへの保存というのは、DB内のカラムにどのように保存されるのでしょうか。

      例えばデータベースにid、name,telなどのカラムがあり、5人分のデータが保存されていたとします。
      そこに並び順[2,6,4,1,3]を後から更新(UPDATE SET WHERE文?)したい場合、
      各行の【並び順(仮)】という新たに追加したカラムに数字が一つずつ格納されるというイメージなのでしょうか。
      また、その場合、idと並び順の関連付けはどのようにすればよいのでしょうか。

      js以外の質問ですが、ご教示いただければ幸甚です。
      どうぞよろしくお願いいたします!!!

      削除
    3. otさん、こんばんわです

      なるほどです
      一度実装しようかと妄想まではした事ある仕組みですが、実装経験はありませんが興味のあった部分ですし喜んで試みてみます

      動くものが出来たら再度追記にて報告させて頂きます、少々お待ち下さいです




      削除
    4. ひとまずサンプルと簡単な説明を記事に埋めておきました

      わかりにくい書き方だったかもしれませんが、およそ想定の挙動になったかなと思います

      内容からおそらく、もっと理解されてる方だと思いますが、念のための説明の部分もありますがご了承下さい

      削除
    5. 超よーちゃん様
      おはようございます。otです。
      昨日は遅い時間までありがとうございました!!
      こんなにも親切にご対応いただけるとは・・・本当に感謝の気持ちでいっぱいです。コーディングを始めて数ヶ月で分からないことだらけなので、解説付きは非常に助かります。
      色々なwebサイトを見ていると、初心者が質問すると厳しいお言葉が返ってくるので今まで怖くて質問できなかったのですが、とても丁寧で親切な回答をいただいて嬉しい限りです。ありがとうございます。
      これからじっくりソースをみていきます。

      その前に確認させていただいてよろしいでしょうか。
      ①ファイルの構成は、
      1.表示用html
      2.post.php
      の2構成ということでよろしいでしょうか。

      ②今までPDOで書いており、mysqli自体初めて知ったのですが、超よーちゃん様のコードをそのまま使わせていただいてもよろしでしょうか。

      ③私の説明不足で申し訳ないのですが、DBの中身をwhileで吐き出す際に、【li】~【/li】の中にif elseif elseifと条件分岐の記述が必要なんです。

      これは何かというと、作ろうとしている【表示リストhtml】は【登録フォームhtml】から登録された内容を表示するものです。
      登録フォームの最初に3つのラジオボタンがあり、この選択によって登録フォームからの入力内容が変わるという仕組みを作っています。
      となると、
      //接続
      while($dat = $res->fetch_assoc()){
      $list = $list.'【li id='.$dat[id].'】'.$dat[id].'【/li】';
      }
      と、
      【ul id="datas"】【? echo $list ?】【/ul】
      の記述ができなくなってしまいますでしょうか。
      もちろん自分で試しますが、できなかった場合はまたお力をお借りしたいです。
      何度も申し訳ありません。
      周りに質問できる方がいないので、超よーちゃん様のお力だけが頼りです!!
      よろしくお願いいたします。頑張ります!!
      図々しくまたご連絡させていただきます。



      削除
    6. とんでもありません、私もまだまだ知識不足で勉強になるので全然問題ありません
      むしろ結構孤独にやってるので助かります

      PDOを利用されているのであれば、サンプルもそのまま書き換えれば大丈夫だと思います

      最後のサンプルは1枚のphpファイルで完結する様になっています、POSTと先も自身のファイルです

      書き忘れましたが、サンプルのファイル名はそのままですと「sortable.php」になっています(javascript部分の$.post()の送信先ファイル名と合わせればなんでもOKです)

      >>while内での条件分岐
      なるほどです
      はっきり言えませんが、仮に使わないデータIDがあっても支障はないので問題はないと思います
      最終的にidが付いたリストのHTMLが表示できればsortable()は簡単に動作します

      またなにかあれば宜しくお願い致します

      削除
    7. こんにちは。
      早速朝からとりかかりました。
      >最後のサンプルは1枚のphpファイルで完結する様になっています
      ということは、1ファイルでリストの表示とDBへの保存ができるということですね。
      で、今やってみたのですが、【syntax error, unexpected 'foreach' (T_FOREACH) in 】とエラーが出てしまいました。
      午前中に2ファイル構成でやった時は、$listの【li】のところの$idが定義されていないというエラーが出てしまい、調べているところです。
      何度もすみません。

      削除
    8. すいません、記事に埋める際の特殊文字の変換がおかしかったかもです
      修正しましたです

      削除
    9. ありがとうございます!
      取り急ぎ、お礼申し上げます。
      引き続き頑張ります。

      削除
    10. 超よーちゃん様
      お世話になっております。お忙しいところ、何度もすみません。
      勝手ながら現状報告をさせていただきます。

      //接続
      while($dat = $res->fetch_assoc()){
      $list = $list.'【li id='.$dat[id].'】'.$dat[id].'【/li】';
      }
      の記述をうまく利用できなかったので、htmlの中にwhile($dat = $res->fetch_assoc()){を入れて条件分岐をさせました。

      【li id='.$dat[id].'】のid設定は、'.$dat['id'].'とすることで、DBのid値を代入することができました。

      今ひっかかってるのが、htmlの記述のところで、【ul id="datas"】でliを囲んでいるのですが、なぜかリストの一行ごとに囲んでおり、1行目だけしかソートできず、うしろの数行はソートできない状態になっています。
      【ul li /li /ul】←この行呑みソートする。
      【ul li /li /ul】
      【ul li /li /ul】・・・といった感じです。

      ul id="datas"をul class="datas"に変更したりといろいろ試したのですができません。
      引き続き解決策を探りたいと思います。

      削除
    11. こんばんわですー
      ulで囲うのはwhile文の中で記述してしまっているのではないでしょうか
      ループが抜けた後でやれば全体を囲えます

      配列のキーの文字列は''が必要なのですね、なるほどです
      環境からか最近要らなかったのでなくしてしまっていました、、
      どちらにせよ''で記述した方が安全そうですね

      削除
  2. できました!
    でも一行ずつ右にずれてます。
    ソートして動かすと整列したり、またずれたり。
    そしてまた新たなエラーが!!
    続きは明日また頑張ります!
    今日もありがとうございました!
    すっごく助かりました!

    返信削除
    返信
    1. こんにちは。お世話になっております。
      昨日のリストの右ズレは頭のUlの位置を変更したら解消しました。
      以下、エラーが出たところを自分なりに直しました。
      ① $sort = $_POST['sort']; → $sort = isset($_POST['sort']);
      ②foreach ($sort as $num => $id) → foreach ((array)$sort as $num => $id)

      $logが未定義というエラーが出たので、$log=0;とするとエラーは出ないのですが、
      ソートの結果が最初の一行しか表示されませんでした。
      この結果表示がなくてもDBのsortカラムに並び順の数字が入っていれば問題ないかと思い、$log = $log.'ID:'.$id.' SORT:'.$num.の行を消して試みたのですがDBには保存されていませんでした。
      よーちゃん様のデータベースではどのように保存されていますでしょうか。
      できればデータベースの画像をupしていただければ幸甚です。
      私のsortカラムは「0」表示のままなので、値が入った状態が見てみたいです。

      毎日しつこくて申し訳ありません。
      お仕事の邪魔をしてご迷惑をおかけしておりますが、どうぞよろしくお願いいたします。

      削除
  3. こんにちわ なるほどです

    データベースの更新が上手くいってなさそうですね
    0のままという事は、sortカラムに入れたいデータが空になっているのかも知れませんですね(サンプルの場合$num)

    phpの未定義エラーについては、こちら環境上発生しないので不足していました、申し訳ありません
    適当に定義しておくかerror_reportingの設定を変更してくださいです

    そのphpファイル内だけにerror_reportingを設定するなら
    error_reporting(E_ALL & ~E_NOTICE);
    でOKです

    返信削除
    返信
    1. ありがとうございます。
      設定してブラウザで何も表示されないのでエラーはないという理解でよろしいでしょうか。

      $numが空かもしれないのですね。
      $logの表示結果は下記のとおりです。

      データベースに保存しました
      0ID:1SORT:1

      引き続き原因を探ります。

      ありがとうございました!

      削除
    2. あ、ログの表示にSORT:1なら、そこまでは正常かもですねー
      解決されたかな

      削除
    3. ご連絡ありがとうございます。
      いえ、まだ解決できてないのです。

      $log = $log.'ID:'.$id.' SORT:'.$num.;を
      $log = 'ID:'.$id.' SORT:'.$num.;とすると、
      ID:1SORT:1
      という結果になりました。
      $log = $log.これの役割がよく分かっていません。すみません。

      ブラウザのコンソール画面で確認すると、Array[]で並び替えたとおりに表示されてはいます。

      解決するのに時間がかかりそうですが、なんとかやってみます。

      削除
    4. $log = $log.としているのは、繰り返し部分なのでデータの追記という感じですね
      $log.をなくした場合は上書きになり繰り返し処理の最後の一回分が$logに代入される形になると思います

      $.postの先は内部的なアクセスなのでエラーやログの確認が少し不便ですが、ログでsort:1となってる事は更新クエリを使い慣れた記述に書き換えてみてはいかがでしょうか

      削除
  4. おはようございます。
    $log = $log.は繰り返しなんですね。調べても分からなかったので勉強になりました。
    ありがとうございます。
    更新クエリの記述を変えてやってみます。
    週明けまでにできればいいな・・・・。
    では、またご連絡いたします!!
    ありがとうございました。

    返信削除
  5. こんにちは。ご無沙汰しております。
    あれから色々試して、ようやくDBに並び順を登録することができました!!
    超よーチャン様のお力がなければ実現できませんでした。感謝しております。
    早速できあがったファイルをwordpressの子テーマに入れて動作確認を行ったのですが
    登録できず><
    wordpressで自作のDBを使うには設定が必要なようで、これからまた長い道のりになりそうです。
    今までありがとうございました!
    またつまずいた時にお邪魔させていただくかもしれません。
    その時はどうぞよろしくお願いいたします。

    返信削除
    返信
    1. こんにちわー
      無事実装良かったです
      WordPressに導入されるのですね、流石です

      また何かありましたら宜しくお願いします

      削除