Overview
NDS.Init.refresh() ships in the main bundle and is available on every page. Pass it the container whose children changed. It walks the component registry and updates every component that has work in or around that container, so no component can be forgotten. Without it, each one needs its own call with its own argument, and every omission fails silently.
The same call covers a table, a card grid, or any list. You never have to remember which component wants the content element and which wants an id.
Components are updated because they are registered, not because you listed them. A page that gains a component later is covered without changing your code.
Components with nothing in the container are left alone. Call it with no argument to sweep the whole document instead.
Nothing here re-sorts, re-pages, or re-filters a result set your server produced. Server pagination and AJAX filters are left exactly as they arrived.
A component whose bundle has not arrived is skipped rather than triggered. It has initialized nothing yet, and it reads the new content when it does load.
Calling it again on settled content leaves the page as it was, so you can call it after every mutation without tracking whether you already did. A client-side filter in scope re-announces its result with nds:filter:change each time.
Example
The shape every screen that edits a list needs: change the rows, then make one call.
const tbody = document.getElementById('requestsTableBody');
// Add, edit, or delete rows however your app does it
tbody.appendChild(buildRow(record));
// Then tell NDS the contents changed
NDS.Init.refresh(tbody);
What It Updates
Components fall into two groups, and the difference matters only if you are debugging. Components that own elements inside the container are re-scanned, so anything new is wired. Components that drive the list from outside it resolve their own connection to the container and update their view.
| Component | What happens |
|---|---|
| Anything inside the rows | Re-scanned and wired: dropmenus, formatted numbers, form controls, copy buttons, tooltips, and every other component with an element in the new content. |
| Filter | Re-resolves its item set so new rows are filterable, and regenerates auto-scanned options so a value that arrived at runtime becomes selectable. |
| Selection | Recounts every widget, so the selected and total figures match the list. |
| Pagination | Recomputed, and your current page is kept. Auto-pagination also re-paginates itself whenever page items are added or removed, so editing a row on page 3 leaves you on page 3. |
| Numbers | Re-scanned. A new value gets locale digits and separators, and a new counter is armed to run when it scrolls into view. A counter that already finished carries data-animated and does not replay: remove that attribute first if you want it to count again. |
| Empty | Nothing to do. It watches its own container and shows or clears the placeholder on its own. |
| Sort | Nothing, by design. See Server-Driven Lists below. |
Server-Driven Lists
When your server does the filtering, sorting, or paging, it has already decided which rows to send and in what order. This call never second-guesses that decision.
- Sorting is never re-applied. A server-sorted page is a slice: the server ordered the whole set and sent you one page of it. Re-sorting that slice in the browser would order it by rendered text and silently contradict the server. If you want late rows folded into a client-side sort, call
NDS.Sort.getInstance(table).refresh()yourself. - AJAX filters are skipped. A filter in AJAX mode owns its result set through its own request. Re-filtering those rows in the browser would match them against
data-filter-valueequality, which is not what a server does with full text search or a join, so rows the server deliberately returned could disappear. It would also shrink your option list to whatever the current page happens to contain. - Server pagination is untouched. A nav built from
data-total-pageskeeps its page count, its active page, and its record figures. Update those withNDS.Pagination.setTotalPages()andNDS.Pagination.updateRecords()when your response arrives. - No request is ever sent. This call only wires markup and recounts what is in the page. It never fetches, and it never submits a filter form.
Teardown
NDS.Init.destroy() is the mirror call. Use refresh() when the contents of a container changed and the container stays. Use destroy() when the container itself is about to go away. It returns the number of instances it released.
A page that loads once never needs this call. Nothing is removed, so nothing has to be released. A framework app is different: it swaps one view for another on every navigation. Each component in the old view holds listeners, observers, and menus that now point at markup the browser has thrown away. Nothing warns you, and the page keeps working, so the cost only shows up after many navigations.
Call it on the root element of the view you are about to remove, not on one list inside it. A filter toolbar can sit beside the grid it drives, so a call on the grid alone misses it.
Teardown is not one way. Each component clears its own init marker, so the same markup can be mounted again later with refresh().
Two components move their element out of your view while it is open. A FAB routes to a dock on <body>. A dropmenu with data-portal sends its open menu to the same place. Teardown puts both back where you wrote them, so the node leaves with your view instead of staying on the page after it.
// Mount a view, then keep it in step as its rows change
NDS.Init.refresh(view);
// Before the view is removed, release everything inside it
NDS.Init.destroy(view);
view.remove();
Usage Guidelines
Framework Views
A framework view needs no readiness check. Call window.NDS?.Init.refresh(view) after mount and NDS.Init.destroy(view) before unmount — that is the whole contract. A view that mounts before the runtime or one of its bundles arrives is picked up by NDS's own startup and arrival scans, and the optional chain covers the one moment where NDS does not exist yet. Do not write a poll or retry helper for this; there is nothing to wait for. The one exception is a component type the first paint never had anywhere: load its bundle once — await NDS.loadBundle('extras') — then call that component's init().
Best Practices
- Call it once after the DOM settles, not once per row. A bulk insert of fifty rows needs one call at the end.
- Pass the container whose children changed, such as the
<tbody>or the grid wrapper. Passing a distant ancestor still works but does more scanning than it needs to. - Prefer it over a single component's
reinit()when a list changed. Reaching for one component is how the others get forgotten, and none of them warn you. - Prefer it over
NDS.Init.initialize(), which re-sweeps and re-tags the whole page. Use that only when you have replaced the entire page body. - You do not need it for content that was in the HTML at load. The loader already initialized that.
- You do not need it after a filter, sort, or pagination interaction. Those components already keep each other in step.
- Call it after your response has been written to the DOM, not when the request resolves. It reads the page, so the rows must be in place.
- Do not call it from a handler for an event it can cause, such as a filter change. That is how a refresh loop starts.
- Tear down what you remove before you remove it. Call
NDS.Init.destroy(element)on it first. Refreshing does not clean up detached elements. - Server-driven list? Read Server-Driven Lists above before adding calls of your own. Most of what you might reach for is deliberately not done for you.
What it does not do
It updates components against the DOM as it stands. It does not fetch, build rows, or manage loading state, and it does not undo work you did by hand: a component you configured through its own API keeps that configuration. It also does not destroy anything. Elements you are about to remove need NDS.Init.destroy() first, described under Teardown above.
Reaching an Instance
A component stores its instance on the element it claims, as an nds{Name} property: el.ndsAccordion, el.ndsChart, el.ndsStepper, el.ndsSort. That property is how you reach an instance from a DOM node, and it is the same property NDS.Init.destroy() reads to find what to release.
Three namespaces also take the element and hand back the instance: NDS.Filter.getInstance(el), NDS.Sort.getInstance(el), and NDS.Upload.getInstance(el). No other namespace has getInstance, so use the element property for the rest.
// The instance sits on the element
document.getElementById('salesChart').ndsChart.render();
// Filter, Sort, and Upload also expose a lookup
const filter = NDS.Filter.getInstance(document.getElementById('resultsFilter'));
JavaScript API
Available on every page as part of the main bundle. No initialization required.