Bug Issue 1566 tcAssign2Tplan Stale Grid After Add - sebiboga/testlink-upgraded GitHub Wiki
Bug fix — Issue #1566: tcAssign2Tplan grid re-renders stale rows after Add (checkbox not disabled, no 'already linked' note until reload)
Issue: #1566
Branch: fix/issue-1566
Status: FIXED & VERIFIED (2026-09-22)
Symptom
In the modern Assign Test Case to Test Plan screen
(gui/templates/testcases/tcAssign2Tplan.html), after clicking + Add the grid is
re-rendered from loadInfo() but the rows keep the PRE-ADD state: the just-linked
plan's checkbox is still enabled (not checked disabled) and the '(already linked)'
note is missing — until the user reloads the page. The ctx.info JS state is correct
(can_do=false, already_linked=true); only the rendered DOM is stale. This is
misleading after the core workflow action and risks a re-check + double-add on a plan
that is actually already linked.
Repro steps (this run, fresh DB)
php tmp/fixtures_1319.php→ A2PDemo (tproject=1), Plan A (tplan=2), Win10 platform (1), A2P-1 tcase=4/tcversion=5 unlinked (can_do=true), A2P-2 v1 linked.- Open
http://localhost:8082/gui/templates/testcases/tcAssign2Tplan.html?tproject_id=1&tcase_id=4&tcversion_id=5(admin/admin). - Tick the Plan A checkbox, click + Add.
- okBox 'Added to 1 test plan(s)' appears; the re-rendered row still shows an ENABLED checkbox and no '(already linked)' note.
Actual (pre-fix), measured 1.2s after the AJAX round-trip:
<input type="checkbox" id="cb_2_1" data-tplan="2" data-platform="1"> (enabled,
unchecked), row text 1 Plan A Win10, while
ctx.info.plans[0].platforms[0].already_linked = true. A stateless page reload
rendered <input ... checked="" disabled=""> + Win10 (already linked) — proving the
data layer was correct and only the DOM was stale.
Root cause chain
renderPlans()(initial call, first load):#planTableis not yet a DataTable → fresh rows are written into#planRowsand the table is initialized. DataTables snapshots that tbody as its "original" DOM.- Add completes →
doAdd()→loadInfo()→renderPlans()again. On this second call the table IS an active DataTable. - The old code order was:
$('#planRows').html(rows)(fresh rows) FIRST, then$('#planTable').DataTable().destroy()(tcAssign2Tplan.html:232-234, pre-fix).destroy()without theremoveflag restores the table's ORIGINAL cached tbody — the pre-add rows from step 1 — replacing the just-written fresh rows. - Re-initialization reads the restored (stale) tbody, so the shown checkbox/link
state is the PRE-ADD state even though
ctx.infowas rebuilt correctly from the BFF. The BFF (api/tcassign2tplan/index.php) and the add itself are sound; the DB link exists and a reload renders correctly.
Blast radius: renderPlans() is the single render path for this screen (init
load and the re-render after Add). No other screen shares it. No BFF change needed.
Fix
Reorder the destroy-then-rebuild so the active DataTable is destroyed BEFORE the tbody is mutated (the report's suggested fix):
// Destroy any ACTIVE DataTable BEFORE mutating #planRows: destroy() restores
// the table's original cached tbody, so rewriting rows afterwards would leave
// the re-render stale. See #1566.
if ($.fn.DataTable.isDataTable('#planTable')) {
$('#planTable').DataTable().destroy();
}
placed at the top of the plans-present branch, and the old destroy block (which ran
after .html(rows)) removed. Why this method: it leaves the pristine-page path intact
(the isDataTable guard is false on first init) and for re-renders guarantees the
tbody mutation lands on a plain HTML table that DataTables then re-reads. Alternative
rejected: $('#planRows').empty()/row-API removal through the live DataTable — more
invasive and DataTables row-API rewrites introduce ordering churn for no benefit.
Verification
Browser regression matrix (admin, fresh DB, Plan B added for the multi-plan case) —
4/4 PASS (see tmp/TLU_Test_Cases.md suite 1577):
- Primary symptom: after Add, the re-rendered row is
checked="" disabled=""with(already linked)note, okBox 'Added to 1 test plan(s)', Add hidden — identical to a fresh page load. - Init-render regression (can_do=false, A2P-2 v2): checkbox
checked disabled, note present, Add hidden, Cancel visible. - Multi-plan re-render: grid with Plan A + Plan B, both selected and Added →
okBox 'Added to 2 test plan(s)', BOTH rows re-rendered
checked disabled+ note. - Events/console:
eventstable shows only expected audit rows (log_level 16: login,audit_tc_added_to_testplan); zero Error/Warning; no new JS console errors.

Files changed
gui/templates/testcases/tcAssign2Tplan.html—renderPlans(): moved the DataTabledestroy()before the#planRowsrewrite (+5/-4 net).tmp/TLU_Test_Cases.md— Regression — Issue #1566 suite 1577 (4/4 PASS).CHANGELOG— KEY BUGFIX entry.- This wiki page + docs mirror + screenshot.
Result
Issue #1566 closed as fixed: the stale re-render after Add is gone — the grid now matches a fresh page load immediately after the link operation, error-free.