CngxReorder
projects/common/interactive/reorder/reorder.directive.ts
Import#
import { CngxReorder } from '@cngx/common/interactive'
Description#
Level-2 atom that turns any flat container into a reorderable list.
Pointer flow. A pointerdown on a drag-handle (any element matching
handleSelector) inside an item (any element matching itemSelector)
starts a drag. Pointer capture stays on the host so the gesture keeps
tracking when the user drifts outside the container. The drop target is
resolved from document.elementFromPoint on every pointermove. The
drag ends on pointerup, pointercancel, or a top-level Escape
press - only the first two emit reordered; Escape cancels the drag
without a mutation.
Keyboard flow. When the focused element is inside an item and the
configured modifier + ArrowLeft / ArrowRight / Home / End is
pressed, the directive emits reordered with the new array and lets
the consumer re-focus the moved item (usually via afterNextRender).
Forms / commit action agnostic. The directive never writes to the
source signal; it only emits events. Composers (e.g.
CngxReorderableMultiSelect) route the emission through their commit
controller so optimistic / pessimistic behaviour stays owned by the
composing component, not by this atom.
Basic chip-strip reorder
<span class="chip-strip" [cngxReorder]="values" (reordered)="apply($event)">
@for (v of values(); track v; let i = $index) {
<span class="chip" [attr.data-reorder-index]="i">
<button cngxReorderHandle aria-label="Verschieben">⋮⋮</button>
{{ v.label }}
</span>
}
</span>Metadata#
Host#
Relationships
Index#
Inputs#
CSS selector matched against pointerdown targets (via
Element.closest) to decide whether the gesture starts. Defaults
cover both the convention-based attribute hook
[data-reorder-handle] and the explicit semantic selector
[cngxReorderHandle] so consumers can pick whichever reads better
in their template.
'[cngxReorderHandle], [data-reorder-handle]'string | nullOptional escape-hatch selector for drag targets. When set and the
pointerdown target matches ignoreSelector (via closest), the
gesture is dropped - useful when the whole item is draggable but
interactive children (close buttons, inline edit fields, menu
triggers) must keep their own click semantics. Applied after
handleSelector, so the two can overlap: e.g.
handleSelector = '[data-reorder-index]' +
ignoreSelector = 'button, a, [contenteditable]' yields
whole-row drag with interactive child exemptions.
null (default) disables the filter - the handleSelector alone
decides whether a drag starts.
nullSignalSignal describing the current, authoritative order. The directive reads it lazily at drag-start and at keyboard-move time so drag sessions always resolve against the freshest value - consumers that mutate the source signal during a drag (rare) still get consistent results.
{ alias: 'cngxReorder' }CSS selector matched against every reorderable child (via
Element.closest). The matched element's data-reorder-index
attribute is parsed as the fromIndex / toIndex used in the
emission.
'[data-reorder-index]'CngxReorderModifierModifier key required for keyboard-driven reorder. Defaults to 'alt'.
'alt'Outputs#
CngxReorderEventEmitted once a drag or keyboard move settles on a new position.
HostBindings#
| Binding | Expression |
|---|---|
[class.cngx-reorder-container] | true |
[class.cngx-reorder-dragging] | dragging() |