非同期通信を使いブラウザ上でデータをリアルタイム更新する

2014-03-07

文字をクリックしてデーターベースを更新する

どういうものか説明するのがちょっと難しいのですが、データ更新の際にフォームを表示して更新するのではなく、表の文字列を直接的に変更する方法です。

サンプル

表の文字をクリックするとテキストフォームが表示され、更新する事が出来ます。なお、今回データベースにはSQLiteを使っています。

PHPのデータ表示部分

<?php
try {
   $db = new PDO("sqlite:05/db/userlist.sqlite");
   $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

   $stmt = $db->prepare("SELECT * FROM userlist ");
   $stmt->execute();
   while ($row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT )) { 
      echo '      <li id="'.$row['id'].'">'."\n"; //データベースのidをliに
      echo '         <p>'.$row['id'].'</p>'."\n"; 
      echo '         <p id="1" class="box">'.$row['name'].'</p>'."\n"; 
      echo '         <p id="2" class="box">'.$row['kana'].'</p>'."\n"; 
      echo '         <p id="3" class="box">'.$row['address'].'</p>'."\n"; 
      echo '         <p id="4" class="box">'.$row['tel'].'</p>'."\n"; 
      echo '      </li>'."\n"; 
   }

} catch (PDOException $e) {
   echo 'データベースへ接続出来ないかエラーです';
}

 ?>
    </ul>

ポイントは1レコードを囲む<li>に、データベースのオートインクリメントでインサートされるidを割り当ててる事と、各要素の<p>に数値を割り当てている点です。

tableで言うと、<tr>が<li>で<td>が<p>です。<li>に振られたidは、更新するレコードのidとして使います。また、<p>に割り当てたidは、どのレコードを更新するかの判定に使います。このidにカラム名を割り当てるのが一番楽ですが、ソースが見えますので、極力避けます。

javascript部分

$(document).ready(function(){
   
    $(".box").dblclick(function(){//ダブルクリックで処理 ←古いです $(document).on('dblclick','.box',function(e){ 
        var num = $(this)[0].id;
        var Id  = $(this).parents("li").attr("id"); //親のid = データのid

        var val   = $("#"+num).text(); //入力したテキスト
        var input = $("<input>").attr("type","text").val($(this).text());
        $(this).html(input); 

        $("input", this).focus().blur(function(){
           dataInsert($(this).val(),num,Id);
           $(this).after($(this).val()).unbind().remove();
        });
    });

    var dataInsert = function(val,num,Id){
       $.ajax({
          type: "POST",
          url: "05data.php",
          data: "val="+val+"&clm="+num+"&id="+Id, //データをPHPに渡す
          success: function(xml){
             $(xml).find("item").each(function(){
                var message = $(this).find("return").text();
                $("#message").html( message ); //メッセージを表示
                  setTimeout(function(){
                     $("#message").slideUp( 100 ); //メッセージを消去
                  },5000);
             });
          }
       });
    }
});

<p>で囲まれた文字列をダブルクリックすると、その箇所にテキストフォームを表示し、離れたときに非同期通信で更新用PHPにデータを渡しています。

データ更新用PHP

<?php
 mb_language("Japanese");
 mb_internal_encoding("UTF-8");
 
 if(!$_POST) exit; //POST来ないときは停止
 
 $str = htmlspecialchars($_POST['val'] , ENT_QUOTES , "UTF-8");
 
 switch($_POST['clm']){
    case 1:
       $column = 'name';
    break;
    case 2:
       $column = 'kana';
    break;
    case 3:
       $column = 'address';
    break;
    case 4:
       $column = 'tel';
    break;
 }

try {
   $db    = new PDO("sqlite:05/db/userlist.sqlite"); //DB接続
   $stmt  = $db->prepare("UPDATE userlist SET ".$column." = :str WHERE id=:id ");
   $stmt -> execute( array(':str'=>$str , ':id'=>$_POST['id'] ) );
   
   $return = '正常に更新されました';
} catch (PDOException $e) {
   $return = 'エラーが発生しました';
}

header("Content-type: application/xml");
echo '<?xml version="1.0" encoding="UTF-8" ?> ' . "\n";
 ?>
<rss>
  <item>
      <return><?php echo $return; ?></return>
  </item>
</rss>

上部で<p =id=”**”>に割り当てられた数字をカラム名に変換する処理をしています。後はただのアップデート文ですね。

気をつけないとならない点として、ソースコードを見ればこのファイル名が第三者に知られてしまいます。サンプルは$_POSTが無い場合は処理を止めていますが、このファイルを直接叩かれても大丈夫なように対策を取る必要が有ります。

表を扱う管理パネルなどでは利用頻度も高いのでは無いでしょうか。いちいちフォームを表示してって面倒です。