jqGrid 實用技巧 (十) 用 custom_func 檢查資料的唯一性

[anti-both]

答 讀 者 Pippen :

很 多 時 候 ,在 資 料 表 的 數 據 ,隨 了 主 鍵 那 個 index number 之 外 ,有 很 多 其 他 的 field 我 們 也 會 設 定 成 唯 一 的 (Unique)。那 如 何 使 用 jqGrid 的 custom_func,在 插 入 資 料 之 前 去 檢 查 一 下 使 用 者 輸 入 的 資 料 在 之 前 是 不 是 已 經 出 現 過 呢 ?

我 自 己 的 習 慣 是 用 jQuery 的 ajax 來 做 。在 下 面 的 例 子 裡 ,我 有 一 個 field 是 rankname,是 用 來 儲 存 職 位 名 稱 的 。在 資 料 表 裡 面 已 經 有 rankcode 作 為 主 鍵 ,所 以 rankname 就 只 是 唯 一 鍵 。

1
2
3
4
5
6
7
...
colModel :[
....
{name:'rankname',index:'rankname',editable:true,edittype:'text',editoptions:{size:20,maxlength:20},editrules:{required:true,custom:true,custom_func:checkRank}},
....
],
...

在 checkRank 裡 面 ,我 用 jQuery.ajax 把 使 用 者 輸 入 的 資 料 傳 到 checkrankname.php 去 檢 查 ,再 按 它 傳 回 來 結 果 處 理 。

特 別 要 留 心 的 是 ,async 必 須 設 置 為 false,意 思 就 是 強 制 它 做 同 步 處 理 ,即 是 要 等 到 有 結 果 傳 回 ,程 式 才 會 繼 續 執 行 下 去 。大 概 有 很 多 朋 友 都 試 過 在 這 個 小 小 的 設 定 上 面 出 問 題 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
function checkRank(posdata, obj){
 var result = null;
 jQuery.ajax({
 async: false,   //this is crucial
 url: 'checkrankname.php',
 type: 'post',
 data: {rankname: posdata.rankname},
 dataType: 'json',
 success: function (data) {
  if (data.success) {
   result = [true, '']
  } else {
   result = [false,'職 位 名 稱 : ' + data.rankname + ' 已 使 用 '];
  }
 },
 error: function () { alert('Error trying to validate rankname ' + posdata.rankname); }
 });
 return result;
 }
...

至 於 那 個 php 檔 ,最 簡 單 的 大 概 就 是 像 下 面 的 樣 子 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
...
$rankname = $_POST['rankname'];

openConnection();
$strSQL = "SELECT rankname FROM rank_table WHERE rankname='$rankname' ";
$rankcheck = mysql_query($strSQL);
$rankcheck2 = mysql_num_rows($rankcheck);

if ($usercheck2 > 0) {
    $data['success'] = false;
    $data['rankname'] = $rankname;
} else {
    $data['success'] = true;
    $data['rankname'] = $rankname;
}

echo json_encode($data);
...

但 也 有 些 時 候 ,要 檢 查 唯 一 值 的 field 多 於 一 個 ,筆 者 也 會 把 custom function 放 在 beforeSubmit 裡 面 執 行 。在 第 二 個 例 子 ,我 們 有 branchcode 和 branchname,是 存 放 分 行 編 碼 和 分 行 名 稱 的 。

1
2
3
4
5
6
7
8
9
10
11
...
$("#list").jqGrid({
...
colModel :[
....
{name:'branchcode',index:'branchcode',editable:true,edittype:'text',editoptions:{size:20,maxlength:20},editrules:{required:true}},
{name:'branchname',index:'branchname',editable:true,edittype:'text',editoptions:{size:100,maxlength:100},editrules:{required:true}},
....
],
pager: '#pager',
...

但 這 次 我 們 不 用 custom_func,而 把 function 放 在 pager 裡 面 的 add 和 edit 裡 面 的 beforeSubmit。

1
2
3
4
5
6
7
8
9
10
...
$("#list").jqGrid('navGrid','#pager',
{edit:true,add:true,del:false,search:true,view:true},
{beforeSubmit:checkBranch},
{beforeSubmit:checkBranch},
{},
{},
{}
);
...

至 於 那 條 function 也 大 同 小 異 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
 function checkBranch(posdata, obj){
  var result = null;
  jQuery.ajax({
  async: false,   //this is crucial
  url: 'checkbranch.php',
  type: 'post',
  data: {branchname: posdata.branchname, branchcode: posdata.branchcode},
  dataType: 'json',
  success: function (data) {
   if (data.success==0) {
   result = [true, '']
   } else if (data.success==1) {
   result = [false,'分 行 名 稱 : ' + data.branchname + ' 已 使 用 '];
   } else if (data.success==2) {
   result = [false,'分 行 編 碼 : ' + data.branchcode + ' 已 使 用 '];
   }
  },
  error: function () { alert('Error trying to validate branch name'); }
  });
  return result;
 }
...

因 為 一 次 過 檢 查 多 於 一 個 field,所 以 傳 回 的 success 變 數 就 由 true / false 變 為 0 / 1 / 2 三 個 可 能 性 了 。

ctleung張先生,男性,肖龍。
職業:I.T. Consultant
簡介:不好好讀書;七尺差五寸,手長過膝,雙耳垂肩;性寬和,寡言語,喜怒不形於色。據說少時曾斬白蛇於鳳凰山下……

This entry was posted in jqGrid and tagged , , , , . Bookmark the permalink.

13 Responses to jqGrid 實用技巧 (十) 用 custom_func 檢查資料的唯一性

  1. Pippen says:

    非常感谢!而且使用了两种不同的入口来判断。
    关于jaon返回的数据格式, 曾经在ajax 的if(data.success)的判断的时候, 无论如何也没有得到false的返回值, 后来才发现是因为返回的数据值的真与假是要使用布尔值的,也就是说返回的要是true和false不是字符串的“ture”和“false”。
    比如我的返回json格式就是:
    {
    “check_column”:”column_name”,”check_value”:” input_value”,”unique_flag”:true
    }
    这里的“unique_flag”的对应的值是布尔值ture, 不是字符串”true”, 提醒大家注意。

    • C.T. Leung says:

      其實用 string 也可以的,只不過你的判斷式要改成 if (data.success==’true’)。我們用if (data.success) 比較多,是因為這種寫法比較簡潔一點吧。

  2. tony says:

    承蒙先前指導, 有漸入佳境了,
    現在有個 動態 editoptions 的問題請教,
    例如 縣市 , 鄉鎮的輸入
    縣市-> 選了台北市, 那 鄉鎮就只剩台北的區可以選,
    edittype = select
    習慣用 formedit, 不曉得 lineedit 是否一樣,
    謝謝 賜教..

    • C.T. Leung says:

      是的,當然是一樣的。

      只不過 form edit 那張 form 裡面只有一個「鄉鎮 select」,而 inline edit 則是一整個 page 那麼多的「鄉鎮 select」。只要你搞清楚每個「鄉鎮 select」的 id 就可以了,操作上是完全沒有分別的。

  3. tony says:

    不好意思, 我主要不是問 form edit 和 inline edit 的差異,
    是要問 動態 editoptions 的做法,
    參照 google 的一些做法, 沒辦法完成, 光是 editoptions:{value:xxxx}
    有 function xxxx(){}
    jqgrid 就顯示不出來了,
    主選項(如:縣市) 還ok, 是固定項目
    次選項(如:鄉鎮) 比較有問題, 如何帶入 主選項的值, 來動態產生 相對應的選單
    謝謝!!
    請再次指教…

    • C.T. Leung says:

      還真看不出,你是問這個。我再三拜讀了你之前的留言,實在完全看不出你不會寫…..

      首先,你那個所謂 Google 出來的做法,筆者很有保留。你應當問問自己,你希望你的程序是在什麼樣的情況下觸發呢?如果是用 editoptions:{value:function_name} 這樣的寫法,它只會在生成表格的時候執行,又怎麼能夠在你選完「主選項」的時候去改變「次選項」呢?

      [題外話,你 jqgrid 不能顯示出來,大概是因為 function xxxx 傳回的東西不對吧,你可以獨立檢查一下 function xxxx 傳回了什麼]

      假如你是希望使用者選完「主選項」,而觸發「次選項」內容的改變,你得問問自己要用那一個 event?

      直觀的,我們當然首先想到 jquery 的 .change() event 吧。

      $("#1st_select_id").change(function(){
      // do something to change the 2nd select
      });

      這個做法是絕對可以的,亦是最常見、最正宗的做法。

      但其實 jqGrid 裡面亦有一個 event,用起來可能會方便一些。

      就是 editrules:{custom:true, custom_func:change2ndselect}。如果你有看過我的文,就知道這是用 custom function 做 data validation 的寫法。它觸發的時間剛好就是使用者輸入完「主選項」的時候。

      function change2ndselect(value,colname){
      // change 2nd select according to value of 1st select
      return [true,""];
      }

      用這個方法的時候,千萬別忘記了一樣要傳回 true 呀。它就是告訴 jqGrid 你的 data validation 沒問題的意思。

      多得同業來信指正,jqGrid 的 data validation 只會在 form submit 的時候觸發,而不會在每個 form field 輸入完成的時候觸發。

  4. kate says:

    版主你好:
    我也想將input的值送到後端檢查資料的唯一性,將結果回傳前端呈現
    目前我遇到一個問題想請教你,如果沒有寫editurl,系統會一直出現錯誤訊息”你尚未設置url”
    若寫了editurl,則前端要在哪裡接收後端回傳的訊息?並將訊息呈現

    我的程式碼如下:
    jQuery(“#masterGrid”).jqGrid({
    editurl:xxx後端網址檢查資料唯一性
    colModel:[
    {editable:true,edittype:’text’,editoptions:{maxlength:7},editrules:{required:true,custom:true, custom_func:validateIp}}
    ]
    });

    謝謝

    • C.T. Leung says:

      如果你希望 jqGrid 幫你把資料儲存到 server,就必須要設定好 editurl。只有在你的 jqGrid 純粹是 display data 的情況之下,才會不用設定 editurl 的。

      我想,你很可能要惡補一下 jqGrid 的 events 了。以 form editing 為例,除非特殊情況,一般來說,data validation 都會在按下 submit 鍵之後才做。讓我們看看 jqGrid 的 documentation,當 user 按下 submit 之後會發生什麼 events 呢?

      – onclickSubmit: fires after the submit button is clicked and the postdata is constructed.
      – beforeCheckValues: fires before checking the values (if checking is defined in colModel via editrules option).
      – beforeSubmit: fires before the data is submitted to the server.
      – afterSubmit: fires after response has been received from server.
      – afterComplete: fires immediately after all actions and events are completed .

      我在這一頁介紹的,是用 column model 的 edit rules 裡面的 custom function 來做 data validation,所以是在 beforeCheckValues 和 beforeSubmit 兩個 events 之間做的。重點是可以在未 submit data 去 sever 之前就做好 data validation。

      而我估計,你想要在 submit 資料之後,才在 server side 做 validation 吧?所以你就看不明白我的例子了。你可以參考同一系列的另一篇文章《jqGrid 實用技巧 (十五) 用 afterSumbit 來做簡單的 error handling》,裡面有詳細介紹如何處理在 afterSubmit 時由 server 傳回的錯誤。

      上面兩個做 data validation 的方法,只是發生的時序不同,其實並沒有說那個比那個好,你要按自己的實際情況來作出合理的選擇啊。

  5. kate says:

    我懂了,感謝版主

Leave a Reply

Your email address will not be published. Required fields are marked *