編輯前重新整理資料
基於 Web 的 CRUD 系統,例如 Editor,本質上是並行的,也就是說,多個使用者可能會同時更新資料。這些使用者可能在同一個辦公室,也可能在世界的兩端,但您不希望發生的情況是,一個使用者對某一行進行更新,然後另一個使用者在沒有意識到資料已變更的情況下提交資訊,從而撤銷了這些變更。
最終,最佳的解決方案是即時更新表格中的資料,這是一個複雜的主題,我們將在未來進行探討(敬請期待!),但在本文中,我想介紹一種機制,該機制可以在最少的程式碼工作量下使用,並且不會中斷現有的程式碼庫:當使用者觸發編輯行時,重新整理要編輯的行(們)的資料。
為此,我們將開發一個新的 按鈕,它可以在觸發編輯之前執行此操作,這是一個可重複使用的元件。結果如下所示(請注意,這看起來與 Editor 中的標準編輯非常相似,但在點擊「編輯」時會使用 Ajax 請求來重新整理資料。顯示此頁面的第二個瀏覽器視窗可用於建立您自己的並行形式,從一個視窗更新另一個視窗中的資料)
姓名 | 職位 | 辦公室 | 薪資 |
---|---|---|---|
姓名 | 職位 | 辦公室 | 薪資 |
可重複使用的按鈕
按鈕函式庫提供了許多內建的按鈕類型(例如用於匯出資料),而 Editor 和 Select 等函式庫可以擴充這些功能。但是按鈕的真正力量在於其定義自訂按鈕的能力,因此您可以建立自己的按鈕並擴充內建按鈕。
可重複使用的自訂按鈕應附加到 $.fn.dataTable.ext.buttons
物件,其中屬性名稱是按鈕的名稱(在 DataTables buttons
設定中使用)。在這種情況下,我們希望按鈕的行為類似於 edit
按鈕類型,因此我們可以擴充它來建立基礎。因此,我們的初始程式碼結構如下所示
$.fn.dataTable.ext.buttons.editRefresh = {
extend: 'edit',
text: 'Edit',
action: function (e, dt, node, config) {
// 1. Get currently selected row ids
// ...
// 2. Ajax request to refresh the data for those ids
// ...
// 3. On success update rows with data
// ...
// 4. And finally trigger editing on those rows
// ...
}
};
分解
現在我們的基本設計已經完成,我們需要做的就是充實每個單獨的元件
- 為了取得即將編輯的行的 ID(以便我們可以向伺服器識別我們感興趣的行),我們可以使用 DataTables
rows().ids()
方法,並結合{selected:true}
選擇器修飾符,以篩選出僅選定的行。 - 由於我們在頁面上已經有了 jQuery,因此我們將使用
$.ajax()
來發出一個簡單的 Ajax 請求,將行 ID 發送到伺服器。請注意使用ajax()
來取得設定的 Editor Ajax URL。 - 更新行只需使用
row().data()
即可完成,並在迴圈中根據其 ID 選取行。請注意,我們應該呼叫draw()
來重新整理表格狀態,但僅當所有選定的行都已更新時才應呼叫。 - 我們可以透過呼叫
edit
按鈕,並使用Function.prototype.call
以確保範圍匹配,從而傳遞我們自己的action
方法的參數,來使用 Editor 定義的edit
按鈕。
將其組合在一起並充實程式碼,我們有
$.fn.dataTable.ext.buttons.editRefresh = {
extend: 'edit',
text: 'Edit',
action: function (e, dt, node, config) {
this.processing( true );
// Get currently selected row ids
var selectedRows = dt.rows({selected:true}).ids();
var that = this;
// Ajax request to refresh the data for those ids
$.ajax( {
url: config.editor.ajax(),
type: 'post',
dataType: 'json',
data: {
refresh: 'rows',
ids: selectedRows.toArray().join(',')
},
success: function ( json ) {
// On success update rows with data
for ( var i=0 ; i<json.data.length ; i++ ) {
dt.row( '#'+json.data[i].DT_RowId ).data( json.data[i] );
}
dt.draw(false);
// And finally trigger editing on those rows
$.fn.dataTable.ext.buttons.edit.action.call(that, e, dt, node, config);
}
} );
}
};
使用按鈕
現在我們只需 照常建立 Editor 和 DataTable 實例,但不是在 buttons
陣列中使用 Editor 的 edit
按鈕,而是使用 editRefresh
- 例如
buttons: [
{ extend: 'create', editor: editor },
{ extend: 'editRefresh', editor: editor },
{ extend: 'remove', editor: editor }
]
這就是客戶端的所有內容!
伺服器端
在伺服器端,我們需要一種能夠從客戶端取得所請求行的資料的方法。這可以在 PHP、.NET 和 NodeJS 的 Editor 函式庫中使用一個相當簡單的 WHERE
條件來完成。
打破鏈條
在許多 Editor 範例中,我們使用單個鏈條來定義 Editor 實例、處理資料並將其傳回客戶端,例如,在 PHP 中,我們可能會使用
$editor = Editor::inst( $db, 'table' )
->fields( ... )
->process( $_POST )
->json();
但是我們要有條件地新增一個 WHERE
陳述式,為了做到這一點,您必須記住以上程式碼可以重寫為
$editor = Editor::inst( $db, 'table' );
$editor->fields( ... );
$editor->process( $_POST );
$editor->json();
有了這個,很容易看出我們如何使用 if
陳述式來檢查是否應該僅擷取某些行。
PHP
在 PHP 中,我們可以使用匿名函式根據行 ID 新增 WHERE ... OR ...
條件列表
$editor = Editor::inst( $db, 'staff' );
$editor->fields(
...
);
// Check if we are getting data for specific rows
if ( isset( $_POST['refresh'] ) ) {
$editor->where( function ($q) use ($editor) {
// Split the CSV ids
$ids = explode( ',', $_POST['ids'] );
for ( $i=0 ; $i<count($ids) ; $i++ ) {
// Remove the row prefix
$id = str_replace( $editor->idPrefix(), '', $ids[$i] );
$q->or_where( 'id', $id );
}
} );
}
// Process and fire back the result
$editor
->process( $_POST )
->json();
.NET
在 .NET 中,類似於上面的 PHP 函式庫,我們可以將 Editor->Where()
方法 與匿名函式一起使用,以根據客戶端的要求建構 WHERE ... OR ...
列表
var editor = new Editor(db, "staff")
.Model<StaffModel>();
if (Request.HasFormContentType && Request.Form.ContainsKey("refresh")) {
editor.Where( q => {
var ids = (Request.Form["ids"].ToString()).Split(',');
for (var i=0 ; i<ids.Length ; i++) {
var id = ids[i].Replace(editor.IdPrefix(), "");
q.OrWhere( "id", id );
}
});
}
var response = editor
.Process(Request)
.Data();
return Json(response);
NodeJS
Editor 的 NodeJS 函式庫使用 Knex 函式庫進行資料庫連線和抽象化,並且透過 Editor.where()
方法公開條件。然後,我們可以使用 Knex 的 orWhere()
方法 來限制 SELECT 陳述式
let editor = new Editor(db, 'staff').fields(
...
);
if (req.body.refresh) {
editor.where(q => {
let ids = req.body.ids.split(',');
for (let i=0 ; i<ids.length ; i++) {
let id = ids[i].replace(editor.idPrefix(), '');
q.orWhere('id', id);
}
})
}
await editor.process(req.body);
res.json(editor.data());
結論
在本文中,我示範了如何使用一個簡單的自訂按鈕,透過在終端使用者觸發編輯時重新整理要編輯的行的資料,來提高 Editor 對高並行系統的適用性。與 Editor 的其餘部分一樣,此方法完全支援多行編輯。
期待未來在 Editor 及其函式庫中看到此功能內建!
如果您想查看完整版本,可取得此範例的完整 Javascript。同樣,也提供了用於開發此文章的 PHP、.NET Core 和 NodeJS 腳本。每個腳本都是演示套件中提供的「staff」範例的小修改。