見出し画像

webix更新処理について(業務アプリ)

前回のサンプルに対し、詳細画面で変更した内容をサーバに送信し、PHP言語でデータベースをUPDATEして、結果をUIに応答する機能を追加しました。画面上の編集操作画面を表示した状態で、Ajax機能を使って(Wbixに関数があります)、サーバ側に更新情報を送信(POSTで依頼)し、受信したPHPでDB更新をします。更新処理のため、画面では、新たに、保存ボタン押下時に、指定したパラメータの妥当性確認(Validate機能)を実装しています。Validate機能もwebixの機能です。正しい値になっていない箇所をピンク色で表示し、エラーメッセージを対象フィールドの下側に表示できます。同時に複数のフィールドチェックを実行し、エラーも同時に表示するため、正しい設定にする操作は1回で完了します。1つづのチェックだと、何度もエラー表示されるので、同時チェックは有効です。今回は、内線番号が数字であることと、入社日が指定してあるかだけのチェックを実装してみました。
内線番号は、attributes:{maxlength: 4}という記述で最大指定長も設定できるので、エラーチェックの対象にはしていません。実際の業務アプリであれば、内線番号は、4桁であることや、入社日は、当日以前の日付であるチェックが必要ですが、今回は。簡単に記述するため。厳密なチェックルールは記載していません。独自の関数を定義してチェックすることや、フィールド間の相関などもチェックできます。詳細は、webixのマニュアルに記述されています。正規化表現を使ったりして、禁足文字のチェックなども可能です。エラーメッセージも、エラー内容に応じて変更することも可能です。
また、内線番号フィールドは一度、値をクリアすると、どのようなフォーマットで入力するかを薄灰色で対象フィールドに記載する機能(placeholder:"4桁以下数字")も実装してみました。

エラーメッセージを表示した画面例です。

尚、今回のサンプルから画面のスタイルを変更しています。コンパクトというスタイルを指定しており、デザインや大きさが前回と異なります。
スタイルシートの指定で、いろいろなデザインにもできます。
skins/compact.css

また、更新処理の機能を記載しましたので、様々な方が操作すると、データが変更されてしまうので、元のデータに戻す初期化ボタンを実装しています。このボタンを押下すると、初期化するかを聞いてくるので、はいを選択すると、サーバ内のデータを初期値も戻すリクエストをUIからサーバに対しAjaxで実施します。(実際にはPOSTメソッドで、初期化を依頼しています)
サンプル画面では、所属組織と内線番号と入社日のみ変更可能です。
操作してみてください。以下のURLで操作できます。


UIソースコードです。webix_sample05.php

<?php
//https://yamasanfarm.sakuraweb.com/webix01/view/ZTEST/webix_sample05.php
// 一覧表のデータは、サーバ側で準備(PHP)
//  日付関数にmomentライブラリを使用
//  phpのログ(php-error.log)は、事前に出力するようにphp.iniで記述
// 更新処理追加(REST_API)

    $VER_INFO ="V01L01";
    $TITLE_INFO = "サンプルWebix02";
    $myfilename = basename(__FILE__);   //自分自身のファイル名取得
    define('ROOT_PATH','/home/sunsun/www/webix01'); //ソースを保存しているパス(動作環境に応じて記述する必要あり)
    define('SUB_FOLDER','/webix01');    //サブフォルダを指定したURL
    $userid = 'admin';
    if(isset($_GET['userid'])){
        $userid = $_GET['userid'];
    }
    $logheader = 'userid='.$userid.', '.$myfilename.':';//ログ出力時のヘッダー情報(自ファイル名,ログインIDを付与)
    error_log($logheader.' start '.$myfilename);
?>
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="<?php  echo SUB_FOLDER; ?>/webix_GPL_1020/webix.css" type="text/css"   charset="utf-8">
        <script src="<?php  echo SUB_FOLDER; ?>/webix_GPL_1020/webix.js"></script>
        <link href="<?php  echo SUB_FOLDER; ?>/webix_GPL_1020/skins/compact.css?<?php echo date('Ymd-H'); ?>" rel="stylesheet" type="text/css">    
        <link rel="icon" href="<?php  echo SUB_FOLDER; ?>/image/webix_64.ico">
        <script src="<?php  echo SUB_FOLDER; ?>/commonlib/moment-with-locales.js"></script>
        <title><?php echo $TITLE_INFO.' ('.$VER_INFO.')' ?></title>
    <style>
    </style>
    </head>
<body>
<script type="text/javascript" charset="utf-8">
webix.i18n.setLocale("ja-JP");
var userid = '<?php echo $userid; ?>';

//本サンプルでは、組織情報をソースに記述する(実際には、この情報もサーバから取得する記述にする必要あり)
var section_options =[{ "id":"1001", "value":"総務課"},{ "id":"1002", "value":"庶務課"}  ,{ "id":"1003", "value":"経理課"},{ "id":"2001", "value":"技術部"},{ "id":"3001", "value":"製造部"}];


//画面の初期化
webix.ui({ padding: 10,
    rows:[
        {view:"label", template:"<span style='font-weight:bold; font-size:180%;'>従業員一覧表<?php echo' ('.$VER_INFO.')' ?></span>"},
        { margin:5, 
            cols:[
                {view:"text", label:"件数", labelWidth:100,name:"lists_count",id:"lists_count",value:0,width:200, labelAlign:"right",readonly:true,inputAlign:"right"},
                {view:"label",lable:"",width:150},
                {view:"button",label: "検索", id:"search_btn",name:"search_btn", width: 100
                    ,click:function(){
                        get_table_lists();
                    }
                },
                {view:"button",label: "初期化", id:"init_btn",name:"init_btn", width: 100, css:"webix_danger"
                    ,click:function(){
                         webix.confirm({
                            title:"確認",
                            ok:"はい", 
                            cancel:"いいえ",
                            text:"テーブルを初期値に戻しますか?"
                         })
                         .then(function(result){  //はいのとき
                            var formData = new FormData();
                            formData.append("userid", userid);
                            var xhr =webix.ajax().sync().post("<?php  echo SUB_FOLDER; ?>/rest_api/ZTEST/ZTEST_init_userinfo.php",formData);
                            var resp =  JSON.parse(xhr.responseText);
                            if(resp.resp =="ok"){
                                get_table_lists();
                                webix.message({type:"success",text:"従業員情報の初期化をしました。"});
                                return;
                            }
                            else{
                                webix.alert("従業員情報の初期化でエラーしました。 code="+resp_info.error_code);
                                return;
                            }
                         }) 
                         .fail(function(){      //いいえの時        
                            webix.message({type:"debug",text:"操作をキャンセルしました。"});
                         });                        
                    }
                },
                {view:"button",label: "新規追加", id:"edit_btn",name:"edit_btn", width: 100,  css:"webix_primary"
                    ,click:function(){
                        webix.alert("本機能は、未実装です。<br>編集操作は、<br>対象行をクリックしてください。");  
                    }
                }
            ]
        },
        {view:"datatable", id:"table01",
           columns:[
               { id:"id"         ,header:"id"                                  ,width:60 , css:{"text-align":"right"},sort:"int"},
               { id:"username"  , header:["名前"    , {content:"textFilter"} ] ,width:100,sort:"string"}, 
               { id:"section_id", header:["所属組織", {content:"selectFilter"}],width:100, options:section_options,sort:"string"},
               { id:"tel_no"    , header:["内線番号", {content:"textFilter"}]  ,width:100, css:{"text-align":"right"},sort:"int"},
               { id:"entry_date", header:["入社日"  , {content:"selectFilter"}],width:120, css:{"text-align":"right"},sort:"string",format:webix.Date.dateToStr("%Y/%m/%d")}
           ],
           data: [],
           resizeColumn:true,
           select:"row",
           clipboard:true,
           on:{
               "onItemClick":function(id){
                    //対象行をクリックしたときの動作(行の情報を取得し、個別画面の各フィールドに代入して画面表示)
                    $$("form_001").clearValidation();
                    var item = this.getItem(id);
                    var select_user_id = item.id;
                    //サーバにuser_idを送信して情報を取得
                    var send_prm = {};
                    send_prm.userid = userid;
                    send_prm.select_user_id = select_user_id;
                    var xhr =webix.ajax().sync().get("<?php  echo SUB_FOLDER; ?>/rest_api/ZTEST/ZTEST_get_userinfo.php",send_prm);
                    var resp = xhr.responseText;
                    var resp_info = JSON.parse(resp);
                    var resp = resp_info.resp;
                    if(resp  == "ok"){
                        if(resp_info.count == 1){
                            $$("id").setValue(resp_info.val_array[0].id);
                            $$("username").setValue(resp_info.val_array[0].username);
                            $$("section_id").setValue(resp_info.val_array[0].section_id);
                            $$("tel_no").setValue(resp_info.val_array[0].tel_no);
                            $$("entry_date").setValue(resp_info.val_array[0].entry_date);
                            form_win.show();                    
                        }
                        else{
                            webix.alert("該当従業員情報が存在しません。");
                            return;
                        }
                    }
                    else{
                        webix.alert("従業員情報の検索でエラーしました。 code="+resp_info.error_code);
                        return;
                    }

                }
           }
        }
    ]
});


//画面描画時に、サーバに一覧情報を取得するAPIをコールして、情報を一覧にセット
get_table_lists();


//サーバから従業員一覧をJSONで取得する関数
function get_table_lists(){
    var send_prm = {};
    send_prm.userid = userid;
    var xhr =webix.ajax().sync().get("<?php  echo SUB_FOLDER; ?>/rest_api/ZTEST/ZTEST_get_users02.php",send_prm);
    var resp = xhr.responseText;
    var resp_info = JSON.parse(resp);
    var resp = resp_info["resp"];
    if(resp_info["resp"] == "ok"){
        $$("table01").parse(resp_info.val_array);
        var array_count = resp_info.val_array.length;
        $$("lists_count").setValue(array_count);
        if(array_count > 0){
            webix.message({type:"success",text:"従業員一覧を読出ししました。"});
        }
        else{
            webix.alert("検索結果は0件です。");
        }
    }
    else{
        webix.message({type:"error",text:"従業員一覧を確認できませんでした。"});
    }
}





//以下は、個別window画面の定義
var form_compo = [
  {view:"label" ,label:"編集後に、保存操作で、一覧に反映します"},
  {view:"text"  ,label:"id"        ,id:"id"                          ,value:"",width:300,labelWidth:100,readonly:true},
  {view:"text"  ,label:"名前"      ,id:"username"                    ,value:"",width:300,labelWidth:100,readonly:true},
  {view:"select",label:"所属組織"  ,id:"section_id",name:"section_id",value:"",width:300,labelWidth:100,options:section_options},
  {view:"text"  ,label:"内線番号"  ,id:"tel_no"    ,name:"tel_no"    ,value:"",width:300,labelWidth:100,attributes:{maxlength: 4},invalidMessage:"数字ではありません", placeholder:"4桁以下数字"},
  {view:"datepicker",label:"入社日",id:"entry_date",name:"entry_date",value:"",width:300,labelWidth:100,format:webix.Date.dateToStr("%Y/%m/%d"),invalidMessage:"未設定です"}
];

//個別編集画面
var form_win = webix.ui({
    view:"window",
    id:"form_win",
    move:true,
    resize:true,
    width:  600,
    height: 500,
    left:   200,
    top:    40,
    head:{
        cols:[
            {template:"編集画面(従業員)", type:"header", borderless:true},  
            {view:"icon", icon:"wxi-close", tooltip:"画面を閉じます", click: function(){
                webix.alert("編集内容は未反映です。");
                form_win.hide();
            }}
        ]
     },
    body:{
    margin:10,
    rows:[{
            view:"form",
            elements:form_compo,
            id:"form_001",
            name:"form_001",
            rules:{
                entry_date:webix.rules.isNotEmpty,
                tel_no:function(value){
                    return webix.rules.isNumber(value)
                }
            }
          },
          {cols:[
              {fillspace:true},
              {view:"button", value: "保存", align:"left", width: 100,height:40,  css:"webix_primary",
                  click:function(){
                  	  $$("form_001").clearValidation();
                      if(!$$("form_001").validate()){
                        //事前チェックvalidationでエラーの場合は、処理を中断
                        return;
                      }
                      var record_id = $$("id").getValue();
                      var item = $$("table01").getItem(record_id);
                      item.username = $$("username").getValue();
                      //サーバに対し更新処理を実行
                      // 更新対象は、所属組織、内線番号、入社日
                      var formData = new FormData();
                      formData.append("userid", userid);
                      formData.append("update_user_id",record_id);  //更新対象のユーザid情報
                      formData.append("section_id",$$("section_id").getValue());    //所属組織
                      formData.append("tel_no",$$("tel_no").getValue());    //内線番号
                      formData.append("entry_date",moment($$("entry_date").getValue()).format("YYYY/MM/DD"));   //入社日
                      var xhr =webix.ajax().sync().post("<?php  echo SUB_FOLDER; ?>/rest_api/ZTEST/ZTEST_update_userinfo.php",formData);
                      var resp =  JSON.parse(xhr.responseText);
                      if(resp.resp =="ok"){
                          //一覧に反映させる
                          item.section_id = $$("section_id").getValue();
                          item.tel_no = $$("tel_no").getValue();
                      
                          //moment関数を利用してフォーマット変換を実施
                          item.entry_date = moment($$("entry_date").getValue()).format("YYYY/MM/DD");
                          $$("table01").refresh();
                          webix.message({type:"success",text:"一覧に反映しました"});
                          form_win.hide();
                      }
                      else{
                          webix.alert("更新操作でエラーが発生しました。 error code="+resp.error_code);
                          return;
                      }
                  }
              },  
              {view:"button", value: "閉じる", align:"left", width: 100,height:40,
                  click:function(){
                      webix.alert("編集内容は未反映です。");
                      form_win.hide();
                  }
              }
          ]
         }
    ]
    }
});
</script>
</body>
</html>

更新処理のサーバ側のソースコードです。ZTEST_update_userinfo.php

 <?php
    //ZTEST_update_userinfo.php
    // UIからのリクエストを受信し、userテーブルを更新する
    //
    $FUNC_INFO = "ZTEST";
    $VER_INFO ="V01L01";
    include_once('env_def.php');
    $myfilename = basename(__FILE__);   //自分自身のファイル名取得
    define('SUB_FOLDER','/webix01');

    $userid = 'admin';
    $logheader = 'userid='.$userid.', '.$myfilename.':';//ログ出力時のヘッダー情報(自ファイル名,ログインIDを付与)

    if($_SERVER["REQUEST_METHOD"] != "POST"){
      //POST以外ははじく
      header("HTTP/1.0 404 Not Found");
      return;
    }

    if(isset($_POST['userid'])){
        $userid = $_POST['userid'];
    }
    $update_user_id = "";
    //更新対象のuser idをパラメータから取り出す
    if(isset($_POST['update_user_id'])){
        $update_user_id = $_POST['update_user_id'];
    }

    $section_id = "";
    if(isset($_POST['section_id'])){
        $section_id = $_POST['section_id'];
    }
    $tel_no = "";
    if(isset($_POST['tel_no'])){
        $tel_no = $_POST['tel_no'];
    }
    $entry_date = "";
    if(isset($_POST['entry_date'])){
        $entry_date = $_POST['entry_date'];
    }



    
    $logheader = 'userid='.$userid.', '.$myfilename.':';//ログ出力時のヘッダー情報(自ファイル名,ログインIDを付与)
   //共通関数の組み込み
    include(ROOT_PATH.'/commonlib/svr_common_lib_v3.php');
    include(ROOT_PATH.'/commonlib/Config.php');

	//パラメータが正しく指定していない場合は、エラー応答
	if($update_user_id == ""){
    	$resp = "ng";
    	$error_code = -1;
    	error_log($logheader.' update_user_id not found ');
    	$json_data = json_encode(compact("resp","error_code"),JSON_UNESCAPED_UNICODE);
    	echo $json_data;    //結果をecho関数で出力
		exit;
	}

    //
    //メインルーチン
    //
    error_log($logheader.' rest api request to '.$myfilename);
    
    $config_obj = get_config_obj();
    //データベース接続する(Mysql)
    $dbh = mysql_connect($config_obj,'app01','mysql_sample');   //mysql_connect関数内でDB接続

	// 静的プレースホルダを指定
   	$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
   	// エラー発生時に例外を投げる
   	$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	
    //トランザクション処理を開始
    $dbh->beginTransaction();

    //検索するSQL文準備
    $update_sql = 'UPDATE users SET section_id = ?,tel_no = ?,entry_date = ?,updated_userid = ?,updated_on =? where id = ?';
    $update_stmt = $dbh->prepare($update_sql);
    $update_stmt->bindValue(1,$section_id  );
    $update_stmt->bindValue(2,$tel_no );
    $update_stmt->bindValue(3,$entry_date );
    $update_stmt->bindValue(4,$userid );
    $update_stmt->bindValue(5,date("Y-m-d H:i:s"));
    $update_stmt->bindValue(6,$update_user_id);
    $update_stmt->execute();
    error_log($logheader.' update users user_id='.$update_user_id);
	$dbh->commit();
	error_log($logheader.' commit');
    $dbh = null;
    
    $resp = "ok";
    $error_code = 0;
    //compact関数とjson_encode関数で、JSON形式の文字列に変換
    $json_data = json_encode(compact("resp","error_code"),JSON_UNESCAPED_UNICODE);
    echo $json_data;    //結果をecho関数で出力
?>

Ajax操作は、検索や1レコードの読み出しは、GETメソッドを使用し、更新や初期化依頼などは、POSTメソッドでjavascriptからPHPに要求を出しています。
GETかPOST以外は、PHP側でのパラメータ取得方法はどちらも一緒です。
UIとサーバ間をJSON形式で情報のやりとりができるので、画面側(Javascript)もサーバ側(PHP)も簡単に情報の送受ができますね。
どうですか、webixでリッチな画面を構成し、Ajax機能でサーバに要求を出し、その要求をPHPで受信し、DB操作を実装する。簡単ですね。
理解できない点などありましたら、質問してください。回答できる範囲でフォローします。なお、サンプルは、一般公開しているサイトなので、すべてのソースコード開示は厳しいです。必要であれば、ローカルに提供することもできますので、こちらも問い合わせで記載してください。

この記事が気に入ったらサポートをしてみませんか?