Fix CKEditor initialization issues in discharge template editor

Fixed the error: Uncaught TypeError: can't access property 'getElementsByTag', b is null

Root Cause:
- CKEditor was not properly destroyed before reinitialization
- No error handling for editor state transitions
- Missing timing delays for DOM readiness when loaded via AJAX
- Inconsistent checking for CKEditor availability

Improvements:
1. Safe destroy pattern - wrap destroy() in try-catch to handle state issues
2. Added typeof check for CKEDITOR instead of window.CKEDITOR
3. Added 100ms setTimeout delay before CKEDITOR.replace() to ensure cleanup
4. Added 150ms delay for initial editor load (especially for AJAX loads)
5. Wrapped all setData() calls in try-catch with textarea fallback
6. Added console warnings for debugging instead of silent failures
7. Check document.readyState before initialization
8. Re-initialize editor check after AJAX template load
9. Added element existence validation before replace()

Changes follow the working pattern from:
- app/Views/PathLab_Report/ultrasound_report_edit.php (safeReplace pattern)
- app/Views/diagnosis/lab_final_report_editor.php (typeof checks)

This ensures the editor works properly when:
- Page loads normally
- Page loads via AJAX (load_form_div)
- User switches between templates using Edit button
- User cancels edit and resets form

Tested scenarios:
- Initial page load
- Edit template -> load data -> CKEditor shows content
- Cancel -> CKEditor resets
- Multiple edit/cancel cycles
This commit is contained in:
DevSoftTech Server 2026-06-06 12:51:21 +05:30
parent 860981a85a
commit 1da16a54d6

View File

@ -325,12 +325,21 @@ $status = (int) ($edit['status'] ?? 1);
fieldTemplateCss.value = '';
}
if (window.CKEDITOR && CKEDITOR.instances[editorFieldId]) {
CKEDITOR.instances[editorFieldId].setData(initialTemplateHtml || '{{CONTENT}}');
var defaultHtml = initialTemplateHtml || '{{CONTENT}}';
if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances && CKEDITOR.instances[editorFieldId]) {
try {
CKEDITOR.instances[editorFieldId].setData(defaultHtml);
} catch (e) {
console.warn('CKEditor setData failed in reset:', e);
var templateHtmlEl = document.getElementById(editorFieldId);
if (templateHtmlEl) {
templateHtmlEl.value = defaultHtml;
}
}
} else {
var templateHtmlEl = document.getElementById(editorFieldId);
if (templateHtmlEl) {
templateHtmlEl.value = initialTemplateHtml || '{{CONTENT}}';
templateHtmlEl.value = defaultHtml;
}
}
@ -393,8 +402,16 @@ $status = (int) ($edit['status'] ?? 1);
}
var html = String(row.template_html || '{{CONTENT}}');
if (window.CKEDITOR && CKEDITOR.instances[editorFieldId]) {
CKEDITOR.instances[editorFieldId].setData(html);
if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances && CKEDITOR.instances[editorFieldId]) {
try {
CKEDITOR.instances[editorFieldId].setData(html);
} catch (e) {
console.warn('CKEditor setData failed in setForm:', e);
var templateHtmlEl = document.getElementById(editorFieldId);
if (templateHtmlEl) {
templateHtmlEl.value = html;
}
}
} else {
var templateHtmlEl = document.getElementById(editorFieldId);
if (templateHtmlEl) {
@ -427,33 +444,50 @@ $status = (int) ($edit['status'] ?? 1);
}
function initTemplateEditor() {
if (!window.CKEDITOR) {
if (typeof CKEDITOR === 'undefined') {
console.warn('CKEditor not loaded');
return;
}
var editorEl = document.getElementById(editorFieldId);
if (!editorEl) {
console.warn('Editor textarea not found:', editorFieldId);
return;
}
CKEDITOR.config.versionCheck = false;
CKEDITOR.config.removePlugins = '';
if (CKEDITOR.instances[editorFieldId]) {
CKEDITOR.instances[editorFieldId].destroy(true);
// Safe destroy - wrap in try-catch to handle any state issues
if (CKEDITOR.instances && CKEDITOR.instances[editorFieldId]) {
try {
CKEDITOR.instances[editorFieldId].destroy(true);
} catch (e) {
console.warn('CKEditor destroy failed for', editorFieldId, '- This is usually safe to ignore', e);
}
}
if (document.getElementById(editorFieldId)) {
CKEDITOR.replace(editorFieldId, {
height: 360,
toolbar: [
{ name: 'document', items: ['Source'] },
{ name: 'clipboard', items: ['Undo', 'Redo'] },
{ name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'RemoveFormat'] },
{ name: 'paragraph', items: ['NumberedList', 'BulletedList', 'Outdent', 'Indent', 'Blockquote'] },
{ name: 'links', items: ['Link', 'Unlink'] },
{ name: 'insert', items: ['Table', 'HorizontalRule', 'SpecialChar'] },
{ name: 'styles', items: ['Format', 'Font', 'FontSize'] },
{ name: 'colors', items: ['TextColor', 'BGColor'] },
{ name: 'tools', items: ['Maximize'] }
]
});
}
// Small delay to ensure DOM is ready and cleanup is complete
setTimeout(function() {
try {
CKEDITOR.replace(editorFieldId, {
height: 360,
toolbar: [
{ name: 'document', items: ['Source'] },
{ name: 'clipboard', items: ['Undo', 'Redo'] },
{ name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'RemoveFormat'] },
{ name: 'paragraph', items: ['NumberedList', 'BulletedList', 'Outdent', 'Indent', 'Blockquote'] },
{ name: 'links', items: ['Link', 'Unlink'] },
{ name: 'insert', items: ['Table', 'HorizontalRule', 'SpecialChar'] },
{ name: 'styles', items: ['Format', 'Font', 'FontSize'] },
{ name: 'colors', items: ['TextColor', 'BGColor'] },
{ name: 'tools', items: ['Maximize'] }
]
});
} catch (e) {
console.error('CKEditor replace failed:', e);
}
}, 100);
}
function toggleCustomSizeFields() {
@ -468,16 +502,29 @@ $status = (int) ($edit['status'] ?? 1);
}
function syncTemplateEditor() {
if (!window.CKEDITOR) {
if (typeof CKEDITOR === 'undefined') {
return;
}
if (CKEDITOR.instances[editorFieldId]) {
CKEDITOR.instances[editorFieldId].updateElement();
if (CKEDITOR.instances && CKEDITOR.instances[editorFieldId]) {
try {
CKEDITOR.instances[editorFieldId].updateElement();
} catch (e) {
console.warn('CKEditor updateElement failed:', e);
}
}
}
initTemplateEditor();
// Initialize editor after a short delay to ensure DOM is ready
// This is especially important when loaded via AJAX
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
setTimeout(initTemplateEditor, 150);
});
} else {
setTimeout(initTemplateEditor, 150);
}
toggleCustomSizeFields();
if (pageSizeEl) {
@ -545,6 +592,12 @@ $status = (int) ($edit['status'] ?? 1);
}
setFormFromTemplateRow(data.row);
// Reinitialize editor after data is loaded to ensure proper state
if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances && !CKEDITOR.instances[editorFieldId]) {
setTimeout(initTemplateEditor, 200);
}
if (fieldTemplateName) {
fieldTemplateName.focus();
}