Overview
The PickList component provides dual list boxes for transferring items between source and target lists. It supports drag-and-drop, button controls for moving items, and custom item templates.
Import
import { MagaryPickList } from 'ng-magary';
Basic Usage
import { Component, signal } from '@angular/core';
import { MagaryPickList } from 'ng-magary';
@Component({
selector: 'app-picklist-demo',
standalone: true,
imports: [MagaryPickList],
template: `
<magary-picklist
[(source)]="sourceProducts"
[(target)]="targetProducts"
sourceHeader="Available"
targetHeader="Selected"
[dragDrop]="true"
(onMoveToTarget)="onMoveToTarget($event)"
(onMoveToSource)="onMoveToSource($event)">
</magary-picklist>
`
})
export class PickListDemoComponent {
sourceProducts = signal([
{ id: 1, label: 'Product 1', category: 'Electronics' },
{ id: 2, label: 'Product 2', category: 'Clothing' },
{ id: 3, label: 'Product 3', category: 'Books' }
]);
targetProducts = signal([]);
onMoveToTarget(event: any) {
console.log('Moved to target:', event.items);
}
onMoveToSource(event: any) {
console.log('Moved to source:', event.items);
}
}
With Custom Item Template
<magary-picklist
[(source)]="sourceItems"
[(target)]="targetItems"
sourceHeader="Available Products"
targetHeader="Selected Products"
[dragDrop]="true">
<ng-template #itemTemplate let-item>
<div class="flex items-center gap-3 p-2">
<img [src]="item.image" class="w-12 h-12 rounded" />
<div class="flex-1">
<h4 class="font-semibold">{{ item.label }}</h4>
<p class="text-sm text-gray-600">{{ item.category }}</p>
</div>
<span class="text-lg font-bold">${{ item.price }}</span>
</div>
</ng-template>
</magary-picklist>
With Drag and Drop
@Component({
template: `
<magary-picklist
[(source)]="available"
[(target)]="selected"
[dragDrop]="true"
[showSourceControls]="true"
[showTargetControls]="true"
(onMoveToTarget)="onMoveToTarget($event)">
<ng-template #itemTemplate let-item>
<div class="picklist-item">
{{ item.label }}
</div>
</ng-template>
</magary-picklist>
`
})
export class PickListDragDropComponent {
available = signal([...]);
selected = signal([]);
onMoveToTarget(event: { items: any[] }) {
console.log('Moved items:', event.items);
}
}
Custom Styling
<magary-picklist
[(source)]="sourceItems"
[(target)]="targetItems"
[sourceStyle]="{ height: '400px', background: '#f8f9fa' }"
[targetStyle]="{ height: '400px', background: '#e9ecef' }"
[dragDrop]="true">
</magary-picklist>
Properties
Array of items in the source list. This is a model property supporting two-way binding.
Array of items in the target list. This is a model property supporting two-way binding.
Header text for the source list.
Header text for the target list.
sourceStyle
Record<string, string | number> | null
default:"null"
Inline styles for the source list container.
targetStyle
Record<string, string | number> | null
default:"null"
Inline styles for the target list container.
Whether to show move buttons for the source list.
Whether to show move buttons for the target list.
Enables drag-and-drop functionality for moving items between lists.
Events
onMoveToTarget
EventEmitter<{ items: any[] }>
Emitted when items are moved from source to target.
onMoveToSource
EventEmitter<{ items: any[] }>
Emitted when items are moved from target to source.
onMoveAllToTarget
EventEmitter<{ items: any[] }>
Emitted when all items are moved from source to target.
onMoveAllToSource
EventEmitter<{ items: any[] }>
Emitted when all items are moved from target to source.
Item Template
Customize item rendering with the itemTemplate:
<magary-picklist [(source)]="source" [(target)]="target">
<ng-template #itemTemplate let-item>
<div class="custom-item">
<span class="item-icon">{{ item.icon }}</span>
<span class="item-label">{{ item.label }}</span>
</div>
</ng-template>
</magary-picklist>
Selection
Items can be selected by:
- Click: Single selection
- Ctrl/Cmd + Click: Multiple selection (toggle)
- Drag: Select and drag multiple items
When controls are visible, four buttons are available:
- Move Right: Move selected items to target
- Move All Right: Move all items to target
- Move Left: Move selected items to source
- Move All Left: Move all items to source
Drag and Drop
When dragDrop is enabled:
- Drag items within the same list to reorder
- Drag items between lists to transfer
- Drop on list container to append to end
- Drop on specific item to insert at position
- Visual feedback during drag operations
Advanced Example
import { Component, signal } from '@angular/core';
interface Product {
id: number;
label: string;
category: string;
price: number;
image: string;
inStock: boolean;
}
@Component({
template: `
<div class="picklist-container">
<h2>Product Selection</h2>
<magary-picklist
[(source)]="availableProducts"
[(target)]="selectedProducts"
sourceHeader="Available Products ({{ availableProducts().length }})"
targetHeader="Selected Products ({{ selectedProducts().length }})"
[sourceStyle]="{ height: '500px' }"
[targetStyle]="{ height: '500px' }"
[dragDrop]="true"
[showSourceControls]="true"
[showTargetControls]="true"
(onMoveToTarget)="onProductsSelected($event)"
(onMoveToSource)="onProductsDeselected($event)">
<ng-template #itemTemplate let-product>
<div class="product-item">
<img [src]="product.image" class="product-image" />
<div class="product-info">
<h4>{{ product.label }}</h4>
<p class="category">{{ product.category }}</p>
<div class="product-meta">
<span class="price">${{ product.price }}</span>
<span class="stock" [class.out-of-stock]="!product.inStock">
{{ product.inStock ? 'In Stock' : 'Out of Stock' }}
</span>
</div>
</div>
</div>
</ng-template>
</magary-picklist>
<div class="selection-summary">
<h3>Total Selected: {{ selectedProducts().length }}</h3>
<p>Total Value: ${{ calculateTotal() }}</p>
</div>
</div>
`,
styles: [`
.product-item {
display: flex;
gap: 1rem;
padding: 0.75rem;
align-items: center;
}
.product-image {
width: 60px;
height: 60px;
object-fit: cover;
border-radius: 0.25rem;
}
.out-of-stock {
color: #ef4444;
}
`]
})
export class ProductPickListComponent {
availableProducts = signal<Product[]>([...]);
selectedProducts = signal<Product[]>([]);
onProductsSelected(event: { items: Product[] }) {
console.log('Selected:', event.items.length, 'products');
this.trackSelection('add', event.items);
}
onProductsDeselected(event: { items: Product[] }) {
console.log('Deselected:', event.items.length, 'products');
this.trackSelection('remove', event.items);
}
calculateTotal(): number {
return this.selectedProducts().reduce((sum, p) => sum + p.price, 0);
}
trackSelection(action: string, items: Product[]) {
// Analytics or backend update
}
}
Styling
Key CSS classes:
magary-pick-list - Main container
picklist-source - Source list container
picklist-target - Target list container
picklist-list - List element
picklist-item - Individual item
picklist-item-selected - Selected item
picklist-item-dragging - Item being dragged
picklist-item-over - Drop target indicator
picklist-controls - Button controls container
Use Cases
- User Permissions: Assign permissions to roles
- Product Selection: Select products for orders or bundles
- Team Assignment: Assign users to teams or projects
- Feature Activation: Enable/disable features
- Category Management: Assign items to categories
Accessibility
- Keyboard navigation with Tab and Arrow keys
- Ctrl/Cmd + Click for multiple selection
- ARIA labels for lists and controls
- Focus management during drag operations
- Screen reader announcements for transfers
The component uses Angular signals and OnPush change detection for optimal performance. Large lists are efficiently rendered with trackBy functions.
Source
View source: projects/ng-magary/src/lib/Data/picklist/picklist.ts:49