Responsive Draggable
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
ResponsiveDraggable Directive
::: info Document Moved The documentation for the ResponsiveDraggable directive has been moved to: ResponsiveDraggable Directive :::
Description
The ResponsiveDraggable directive implements fully responsive drag functionality for widgets in the visual editor. This directive is essential for allowing users to interact with widgets through drag and drop, respecting different breakpoints and layout systems.
Key Features
- Complete support for responsive design with different breakpoints
- Compatibility with different positioning units (px, %, vw, vh)
- Integration with different layout systems (standard, grid, flex)
- Bidirectional updates between UI and data model
- Optimized management of touch and mouse events
- Configurable constraint and boundary systems
Import
import { ResponsiveDraggableDirective } from '@widgets-editor/shared-ui';
API
Inputs
| Name | Type | Default Value | Description |
|---|---|---|---|
ngDraggable |
boolean |
true |
Enables or disables the dragging functionality |
widget |
Widget |
- | Widget configuration object (required) |
activeBreakpoint |
BreakpointKey |
'base' |
Current active breakpoint |
parentLayoutType |
'standard' | 'grid' | 'flex' |
'standard' |
Layout type of the parent container |
dragHandle |
string |
'.drag-handle' |
CSS selector for the drag handle element |
dragBoundary |
string | Element |
null |
CSS selector or Element that defines the drag boundaries |
gridSize |
number |
1 |
Grid size for snap-to-grid functionality |
snapToGrid |
boolean |
false |
Enables snap-to-grid during dragging |
Outputs
| Name | Type | Description |
|---|---|---|
dragStart |
EventEmitter<DragEvent> |
Emitted when dragging starts |
dragMove |
EventEmitter<DragEvent> |
Emitted during dragging |
dragEnd |
EventEmitter<DragEvent> |
Emitted when dragging ends |
widgetChanged |
EventEmitter<Widget> |
Emitted when the widget's position changes |
Methods
| Name | Parameters | Return | Description |
|---|---|---|---|
isDragging |
() |
boolean |
Returns whether the element is currently being dragged |
reset |
() |
void |
Resets the element to its original position |
updatePosition |
(x: number, y: number) |
void |
Manually updates the position of the element |
Implementation in Widgets
Basic Implementation
HTML Template
<div class="widget-container"
libResponsiveDraggable
[widget]="widget"
[activeBreakpoint]="activeBreakpoint"
[dragHandle]="'.header'"
(widgetChanged)="onWidgetChanged($event)">
<div class="header">Drag me</div>
<div class="content">Widget content...</div>
</div>
TypeScript Component
@Component({
// ...
imports: [
// Other imports...
ResponsiveDraggableDirective
],
// ...
})
export class MyWidgetComponent {
@Input() widget!: Widget;
@Input() activeBreakpoint: BreakpointKey = 'base';
@Output() widgetUpdate = new EventEmitter<Widget>();
onWidgetChanged(updatedWidget: Widget): void {
this.widget = updatedWidget;
this.widgetUpdate.emit(updatedWidget);
}
}
With Constraints
<div class="widget-container"
libResponsiveDraggable
[widget]="widget"
[activeBreakpoint]="activeBreakpoint"
[dragBoundary]="'.editor-canvas'"
[snapToGrid]="true"
[gridSize]="8"
(dragStart)="onDragStart()"
(dragEnd)="onDragEnd()">
<!-- Widget content -->
</div>
In Grid Layout
@Component({
// ...
})
export class GridWidgetComponent {
@Input() widget!: Widget;
@Input() activeBreakpoint: BreakpointKey = 'base';
@Output() widgetUpdate = new EventEmitter<Widget>();
readonly containerStyles = computed(() => {
// Get the widget's position for the current breakpoint
const position = this.getWidgetPositionForBreakpoint();
return {
gridColumn: `${position.gridColumn} / span ${position.gridColumnSpan || 1}`,
gridRow: `${position.gridRow} / span ${position.gridRowSpan || 1}`,
// Other styles...
};
});
private getWidgetPositionForBreakpoint(): GridPosition {
const breakpoint = this.activeBreakpoint;
return this.widget.responsive?.[breakpoint]?.position || this.widget.position;
}
onWidgetChanged(updatedWidget: Widget): void {
this.widget = updatedWidget;
this.widgetUpdate.emit(updatedWidget);
}
}
Performance Considerations
- The directive uses the
@angular/cdk/drag-dropmodule internally for optimal performance - For large numbers of draggable elements, consider using virtual scrolling
- The event emission is throttled to prevent excessive updates
- Transforms are used instead of position changes for smoother animations
- Calculated styles are memoized to minimize recalculations
Integration with Advanced Layout Systems
The directive integrates with:
- CSS Grid for grid-based layouts
- Flexbox for flexible layouts
- Standard absolute positioning
Depending on the parentLayoutType input, the directive will calculate and apply the appropriate transformations to maintain the expected behavior in different layout systems.