內嵌編輯
更新:如果您正在尋找 DataTables 的完整編輯解決方案,Editor 現在已推出,可以在幾分鐘內為您的表格新增編輯功能。
這篇部落格文章是在 DataTables 1.10 發布之前撰寫的,並未使用 1.10 中的新 API 和功能。它保留作為參考,但請參閱手冊以了解如何使用 DataTables 的說明。
在現代的 Web 應用程式中,表格的一個常見用途是顯示一個可讓最終使用者修改的資訊網格 - 一個典型的 CRUD(建立、讀取、更新、刪除) 情境。一個例子是 Web 應用程式的使用者列表,其中管理員可以在表格視圖中即時更新使用者詳細資訊。
呈現此表格的編輯介面有一百萬種不同的方式,而您希望使用的方法將取決於您希望它如何與網站/應用程式的其餘部分互動。您可能希望有一個浮在表格頂部的燈箱編輯表單,或者您可以使用類似 jEditable 的函式庫一次編輯一個儲存格。我通常避免為 DataTables 提供編輯外掛程式,因為它應該如何實施會因情況而異,而且這裡沒有一種尺寸適合所有情況。
幸運的是,使用 DataTables API,可以非常輕鬆地創建一個針對您的特定設置量身定制的 CRUD 介面。在此範例中,我將展示如何創建一個提供整行內嵌編輯的介面。本教學結束時的結果如下所示
表格
與往常一樣,我們需要一個表格作為起點。為此,我將以我的 Conditional-CSS 的瀏覽器支援標準表格為基礎,製作可編輯的表格,並添加兩個額外的列,一個用於編輯按鈕,另一個用於刪除按鈕。當然,這些可以根據您的需要進行樣式設置或自定義(圖像等)。我還將在表格上方添加一個用於創建新列的連結。標記如下所示
<p><a id="new" href="">Add new row</a></p>
<table cellpadding="0" cellspacing="0" border="0" class="display" id="example">
<thead>
<tr>
<th>Rendering engine</th>
<th>Browser</th>
<th>Platform(s)</th>
<th>Engine version</th>
<th>CSS grade</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr class="odd gradeX">
<td>Trident</td>
<td>Internet Explorer 4.0</td>
<td>Win 95+</td>
<td class="center">4</td>
<td class="center">X</td>
<td><a class="edit" href="">Edit</a></td>
<td><a class="delete" href="">Delete</a></td>
</tr>
...
</tbody>
</table>
DataTables 的初始化非常簡單
$(document).ready(function() {
var oTable = $('#example').dataTable();
} );
編輯模式
在三個編輯功能(建立、編輯和刪除)中,編輯功能是我們將在這裡處理的第一個功能。我這樣做的方法是簡單地將要編輯的行中每個儲存格的內容替換為一個 input 標籤,並將其值設定為儲存格的內容。這不會影響 DataTables 提供的功能,例如排序和篩選,因為 DataTables 會維護來自儲存格的資料內部快取(以便更快地存取資料)- 因此我們可以對 DOM 元素執行任何需要的操作。
這個函式非常簡單
function editRow ( oTable, nRow )
{
var aData = oTable.fnGetData(nRow);
var jqTds = $('>td', nRow);
jqTds[0].innerHTML = '<input type="text" value="'+aData[0]+'">';
jqTds[1].innerHTML = '<input type="text" value="'+aData[1]+'">';
jqTds[2].innerHTML = '<input type="text" value="'+aData[2]+'">';
jqTds[3].innerHTML = '<input type="text" value="'+aData[3]+'">';
jqTds[4].innerHTML = '<input type="text" value="'+aData[4]+'">';
jqTds[5].innerHTML = '[Save]()';
}
如您所見,函式 editRow() 採用兩個參數
-
- oTable - DataTables 實例
-
- nRow - 要編輯的行的 TR 節點
對於行中可以編輯的每個儲存格,我們插入輸入標籤並設定其值(透過使用 fnGetData 來獲取行的資料)。請注意,「編輯」連結也會更新為現在顯示「儲存」,以向最終使用者指示再次點擊時將執行的動作。顯然,這是一個非常簡單的情況,它可以很容易地擴展到包含 select 元素或您希望使用的任何其他類型的輸入。
function saveRow ( oTable, nRow )
{
var jqInputs = $('input', nRow);
oTable.fnUpdate( jqInputs[0].value, nRow, 0, false );
oTable.fnUpdate( jqInputs[1].value, nRow, 1, false );
oTable.fnUpdate( jqInputs[2].value, nRow, 2, false );
oTable.fnUpdate( jqInputs[3].value, nRow, 3, false );
oTable.fnUpdate( jqInputs[4].value, nRow, 4, false );
oTable.fnUpdate( '[Edit]()', nRow, 5, false );
oTable.fnDraw();
}
要將使用者編輯的資訊儲存回表格中(以便它可以像平常一樣進行排序和篩選),我們使用 fnUpdate API 方法。fnUpdate 會將給定的值寫入 TD 儲存格節點,有效地將我們在 editRow 函式中插入的 input 元素替換為新值。請注意,傳遞給 fnUpdate 的第四個參數為 false,表示 DataTables 不應重新繪製表格 - 否則我們將在此處執行六次完整的重新繪製,而僅在所有更新完成後執行一次就足夠了。
現在我們有了編輯和儲存功能,我們需要將適當的事件處理程式添加到文件中以呼叫它們。為此,我們將 live 事件處理程式附加到編輯儲存格中的 a 標籤,這將決定要執行的操作。點擊「編輯」儲存格時,我們可能會處於三種狀態
- 目前沒有正在編輯的行
- 正在編輯此行,應儲存
- 正在編輯不同的行 - 應取消編輯並編輯此行
為了追蹤正在編輯的行,我們有一個名為 nEditing 的變數來儲存對它的參考 - 從這裡我們可以決定我們處於什麼狀態。因此,我們可以為我們的初始化程式碼建立以下內容
$(document).ready(function() {
var oTable = $('#example').dataTable();
var nEditing = null;
$('#example a.edit').live('click', function (e) {
e.preventDefault();
/* Get the row as a parent of the link that was clicked on */
var nRow = $(this).parents('tr')[0];
if ( nEditing !== null && nEditing != nRow ) {
/* A different row is being edited - the edit should be cancelled and this row edited */
restoreRow( oTable, nEditing );
editRow( oTable, nRow );
nEditing = nRow;
}
else if ( nEditing == nRow && this.innerHTML == "Save" ) {
/* This row is being edited and should be saved */
saveRow( oTable, nEditing );
nEditing = null;
}
else {
/* No row currently being edited */
editRow( oTable, nRow );
nEditing = nRow;
}
} );
} );
新增列
這就是最複雜的部分 - 從這裡開始就一路下坡了!要將新列添加到表格中,DataTables 提供了 fnAddData API 方法。我們可以結合使用此方法和上面的 editRow 函式來建立新列並立即將其置於編輯模式。在這裡,我們將事件處理程式附加到表格頂部的特殊連結,在文件就緒函式中
$('#new').click( function (e) {
e.preventDefault();
var aiNew = oTable.fnAddData( [ '', '', '', '', '',
'[Edit]()', '[Delete]()' ] );
var nRow = oTable.fnGetNodes( aiNew[0] );
editRow( oTable, nRow );
nEditing = nRow;
} );
這裡有兩點需要考慮:首先,fnAddData 返回一個索引數組,每個索引指向儲存在 DataTables 中新列的列資訊(它是一個數組,因為 fnAddData 可以一次新增多列)。從這個索引中,我們可以使用 fnGetNodes 來獲取要編輯的 tr 元素。其次,我們將 nEditing 變數設定為新列,以便編輯/儲存處理程式知道在點擊時應儲存它。
刪除列
為了總結三個編輯功能,我們現在只需要添加從表格中刪除列的選項,這可以使用 DataTables 提供的 fnDeleteRow API 方法輕鬆完成 - 只需傳遞對要刪除的列的參考即可
$('#example a.delete').live('click', function (e) {
e.preventDefault();
var nRow = $(this).parents('tr')[0];
oTable.fnDeleteRow( nRow );
} );
結論
在本文中,我介紹了一種可能的方法,說明如何在 DataTables 中建立 CRUD 介面。此處顯示的實作有意保持簡單,以便展示 DataTables API 的使用,並展示此類介面可以輕鬆地為您的網站/應用程式建立和自訂。
值得注意的是,此實作存在一些限制,以及可以改進的領域
- 目前資料不會儲存到伺服器,只會儲存到本機 DataTables 實例 - 因此重新載入會將表格還原為原始狀態。需要一個 XHR 呼叫到伺服器才能將使用者輸入資訊儲存到資料庫中(在 saveRow 中)。
- 欄數和可以編輯的欄是硬編碼的 - 如果可以指定一個欄索引數組,指出哪些欄應該可編輯,那就太好了。
- 目前輸入類型僅限於文字輸入 - 諸如 select 輸入之類的選項將是理想的。
- 可以實施 UI 改進,例如自動焦點和在「返回」時儲存,以讓最終使用者更輕鬆地使用。
我認為這很有可能被寫成外掛程式 - 有人願意接受將其建構成 DataTables 的完整外掛程式的挑戰嗎?:-)
有關此文章的評論和討論,請見論壇。