FCKeditor/CKEditor 使用 `` 或 `` 模擬編輯區,實際 `` 隱藏且僅在提交前同步內容。導致: RequiredFieldValidator 驗證失效:檢查的是隱藏 textarea 初始空值 需提交兩次才觸發驗證:第一次提交同步內容,第二次才驗證通過 客戶端驗證無法即時運作:編輯器實例尚未就緒時驗證腳本已執行 方案一:停用客戶端驗證,僅伺服器端驗證 (快速修補) <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="fckEditor" Display="Dynamic" EnableClientScript="False" ErrorMessage="請輸入內容"> </asp:RequiredFieldValidator> ✅ 簡單有效 ❌ 無即時回饋,使用者體驗差 方案二:CustomValidator + CKEditor JavaScript API (推薦,完整體驗) 1. 客戶端驗證函數 <script type="text/javascript"> var editorInstance = null; // CKEditor 實例就緒事件 function CKEDITOR_OnComplete(editor) { editorInstance = editor; } // CustomValidator 客戶端驗證函數 function ValidateEditorContent(source, arguments) { if (!editorInstance) { arguments.IsValid = false; return; } // 取得純文字內容 (移除 HTML 標籤) var text = editorInstance.getData().replace(/<[^>]*>/g, '').trim(); arguments.IsValid = text.length > 0; } </script> 2. 頁面標記 <!-- CKEditor 載入 --> <script src="/ckeditor/ckeditor.js"></script> <textarea id="fckEditor" name="fckEditor" runat="server"></textarea> <script>CKEDITOR.replace('fckEditor', { on: { instanceReady: CKEDITOR_OnComplete } });</script> <!-- 驗證控制項 --> <asp:CustomValidator ID="CustomValidator1" runat="server" ControlToValidate="fckEditor" Display="Dynamic" ErrorMessage="內容不得為空" ClientValidationFunction="ValidateEditorContent" OnServerValidate="ValidateEditor_ServerValidate"> </asp:CustomValidator> 3. 伺服器端驗證 (雙重保障) protected void ValidateEditor_ServerValidate(object source, ServerValidateEventArgs args) { // 移除 HTML 標籤後檢查 string html = fckEditor.Value ?? ""; string text = Regex.Replace(html, "<[^>]*>", "").Trim(); args.IsValid = !string.IsNullOrEmpty(text); } FCKeditor 2.x 版本特定寫法 <script> // FCKeditor 專用 API var oEditor = null; function FCKeditor_OnComplete(editorInstance) { oEditor = editorInstance; } function FckValidate(source, arguments) { if (!oEditor) { arguments.IsValid = false; return; } // FCKeditor 取得 XHTML 內容 var value = oEditor.GetXHTML(true); // 簡單移除標籤檢查 (或使用 jQuery: $(value).text().trim()) arguments.IsValid = (value.replace(/<[^>]*>/g, '').trim().length > 0); } </script> <asp:CustomValidator ID="CustomValidator1" runat="server" ClientValidationFunction="FckValidate" OnServerValidate="ValidFck" ControlToValidate="fck" ErrorMessage="沒有填寫" Display="Dynamic"> </asp:CustomValidator> 進階:整合 jQuery Validate / ASP.NET Core 驗證屬性 jQuery Validate 客製規則 $.validator.addMethod("ckeditorRequired", function(value, element) { var editor = CKEDITOR.instances[element.id]; if (!editor) return false; var text = editor.getData().replace(/<[^>]*>/g, '').trim(); return text.length > 0; }, "請輸入內容"); // 套用規則 $("#myForm").validate({ rules: { fckEditor: { ckeditorRequired: true } } }); ASP.NET Core Model 驗證屬性 public class RichTextRequiredAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext context) { if (value == null) return new ValidationResult(ErrorMessage); string text = Regex.Replace(value.ToString(), "<[^>]*>", "").Trim(); return string.IsNullOrEmpty(text) ? new ValidationResult(ErrorMessage) : ValidationResult.Success; } } // ViewModel 使用 public class ArticleVm { [RichTextRequired(ErrorMessage = "文章內容不得為空")] public string Content { get; set; } } 常見陷阱與解決 問題原因解決 驗證函數找不到編輯器實例驗證腳本在 `instanceReady` 前執行在 `CKEDITOR_OnComplete` / `FCKeditor_OnComplete` 中快取實例,驗證函數檢查 null 只輸入空白/換行通過驗證未處理 ` `、換行標籤伺服器端用 `Regex.Replace(html, "<[^>]*>| |\\s", "")` 徹底清理 UpdatePanel 部分更新後驗證失效編輯器實例重建,舊引用失效`pageLoad()` 重新綁定、`ScriptManager.RegisterStartupScript` 重新初始化 內容過長導致驗證效能問題正則替換大量 HTML先檢查 `editor.getData().length > threshold` 快速通過,或使用 `editor.document.getBody().getText()` 直接取純文字 總結 富文本編輯器非空驗證的核心在於正確取得編輯器實例並提取純文字內容。CustomValidator + 客戶端 API + 雙端驗證 是標準解法。現代專案建議:前端使用 jQuery Validate / Vue/React 表單驗證庫 + CKEditor 5 整合,後端以Model 驗證屬性統一防禦,完全取代 WebForms 驗證控制項體系。 上一篇文章: ASP.NET TreeView 建構多層級複選輸入介面:級聯選取、彈出視窗、資料綁定與回傳值組裝 下一篇文章: ASP.NET HTTP 模組實作 SQL 注入防護:全域攔截 QueryString/Form/Cookie 危險字元
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="fckEditor" Display="Dynamic" EnableClientScript="False" ErrorMessage="請輸入內容"> </asp:RequiredFieldValidator>
✅ 簡單有效 ❌ 無即時回饋,使用者體驗差
<script type="text/javascript"> var editorInstance = null; // CKEditor 實例就緒事件 function CKEDITOR_OnComplete(editor) { editorInstance = editor; } // CustomValidator 客戶端驗證函數 function ValidateEditorContent(source, arguments) { if (!editorInstance) { arguments.IsValid = false; return; } // 取得純文字內容 (移除 HTML 標籤) var text = editorInstance.getData().replace(/<[^>]*>/g, '').trim(); arguments.IsValid = text.length > 0; } </script>
<!-- CKEditor 載入 --> <script src="/ckeditor/ckeditor.js"></script> <textarea id="fckEditor" name="fckEditor" runat="server"></textarea> <script>CKEDITOR.replace('fckEditor', { on: { instanceReady: CKEDITOR_OnComplete } });</script> <!-- 驗證控制項 --> <asp:CustomValidator ID="CustomValidator1" runat="server" ControlToValidate="fckEditor" Display="Dynamic" ErrorMessage="內容不得為空" ClientValidationFunction="ValidateEditorContent" OnServerValidate="ValidateEditor_ServerValidate"> </asp:CustomValidator>
protected void ValidateEditor_ServerValidate(object source, ServerValidateEventArgs args) { // 移除 HTML 標籤後檢查 string html = fckEditor.Value ?? ""; string text = Regex.Replace(html, "<[^>]*>", "").Trim(); args.IsValid = !string.IsNullOrEmpty(text); }
<script> // FCKeditor 專用 API var oEditor = null; function FCKeditor_OnComplete(editorInstance) { oEditor = editorInstance; } function FckValidate(source, arguments) { if (!oEditor) { arguments.IsValid = false; return; } // FCKeditor 取得 XHTML 內容 var value = oEditor.GetXHTML(true); // 簡單移除標籤檢查 (或使用 jQuery: $(value).text().trim()) arguments.IsValid = (value.replace(/<[^>]*>/g, '').trim().length > 0); } </script> <asp:CustomValidator ID="CustomValidator1" runat="server" ClientValidationFunction="FckValidate" OnServerValidate="ValidFck" ControlToValidate="fck" ErrorMessage="沒有填寫" Display="Dynamic"> </asp:CustomValidator>
$.validator.addMethod("ckeditorRequired", function(value, element) { var editor = CKEDITOR.instances[element.id]; if (!editor) return false; var text = editor.getData().replace(/<[^>]*>/g, '').trim(); return text.length > 0; }, "請輸入內容"); // 套用規則 $("#myForm").validate({ rules: { fckEditor: { ckeditorRequired: true } } });
public class RichTextRequiredAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext context) { if (value == null) return new ValidationResult(ErrorMessage); string text = Regex.Replace(value.ToString(), "<[^>]*>", "").Trim(); return string.IsNullOrEmpty(text) ? new ValidationResult(ErrorMessage) : ValidationResult.Success; } } // ViewModel 使用 public class ArticleVm { [RichTextRequired(ErrorMessage = "文章內容不得為空")] public string Content { get; set; } }
富文本編輯器非空驗證的核心在於正確取得編輯器實例並提取純文字內容。CustomValidator + 客戶端 API + 雙端驗證 是標準解法。現代專案建議:前端使用 jQuery Validate / Vue/React 表單驗證庫 + CKEditor 5 整合,後端以Model 驗證屬性統一防禦,完全取代 WebForms 驗證控制項體系。
問題背景 接續上文 TextChanged 事件分析,本文聚
為什麼單純 Hash 不夠? 哈希函數 (MD5, SHA-
前言:超越官網後台的客服體驗 微信規定:用戶主動發訊後 48
為什麼需要母版頁? 在開發多人協作的畢業專題或企業專案時,網