![見出し画像](https://assets.st-note.com/production/uploads/images/132699713/rectangle_large_type_2_89291ac72090c6884476c1688fbef283.jpeg?width=1200)
webix更新処理について(業務アプリ)
前回のサンプルに対し、詳細画面で変更した内容をサーバに送信し、PHP言語でデータベースをUPDATEして、結果をUIに応答する機能を追加しました。画面上の編集操作画面を表示した状態で、Ajax機能を使って(Wbixに関数があります)、サーバ側に更新情報を送信(POSTで依頼)し、受信したPHPでDB更新をします。更新処理のため、画面では、新たに、保存ボタン押下時に、指定したパラメータの妥当性確認(Validate機能)を実装しています。Validate機能もwebixの機能です。正しい値になっていない箇所をピンク色で表示し、エラーメッセージを対象フィールドの下側に表示できます。同時に複数のフィールドチェックを実行し、エラーも同時に表示するため、正しい設定にする操作は1回で完了します。1つづのチェックだと、何度もエラー表示されるので、同時チェックは有効です。今回は、内線番号が数字であることと、入社日が指定してあるかだけのチェックを実装してみました。
内線番号は、attributes:{maxlength: 4}という記述で最大指定長も設定できるので、エラーチェックの対象にはしていません。実際の業務アプリであれば、内線番号は、4桁であることや、入社日は、当日以前の日付であるチェックが必要ですが、今回は。簡単に記述するため。厳密なチェックルールは記載していません。独自の関数を定義してチェックすることや、フィールド間の相関などもチェックできます。詳細は、webixのマニュアルに記述されています。正規化表現を使ったりして、禁足文字のチェックなども可能です。エラーメッセージも、エラー内容に応じて変更することも可能です。
また、内線番号フィールドは一度、値をクリアすると、どのようなフォーマットで入力するかを薄灰色で対象フィールドに記載する機能(placeholder:"4桁以下数字")も実装してみました。
![](https://assets.st-note.com/img/1709382910245-Ntp8lMCpHW.png)
エラーメッセージを表示した画面例です。
![](https://assets.st-note.com/img/1709383000077-CAeTbuObIp.png)
尚、今回のサンプルから画面のスタイルを変更しています。コンパクトというスタイルを指定しており、デザインや大きさが前回と異なります。
スタイルシートの指定で、いろいろなデザインにもできます。
skins/compact.css
また、更新処理の機能を記載しましたので、様々な方が操作すると、データが変更されてしまうので、元のデータに戻す初期化ボタンを実装しています。このボタンを押下すると、初期化するかを聞いてくるので、はいを選択すると、サーバ内のデータを初期値も戻すリクエストをUIからサーバに対しAjaxで実施します。(実際にはPOSTメソッドで、初期化を依頼しています)
サンプル画面では、所属組織と内線番号と入社日のみ変更可能です。
操作してみてください。以下のURLで操作できます。
![](https://assets.st-note.com/img/1709383787533-ijpxsquEoL.png?width=1200)
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操作を実装する。簡単ですね。
理解できない点などありましたら、質問してください。回答できる範囲でフォローします。なお、サンプルは、一般公開しているサイトなので、すべてのソースコード開示は厳しいです。必要であれば、ローカルに提供することもできますので、こちらも問い合わせで記載してください。