Splitting a backing array into two observables
Since we are concerned with one source but need to output a subset of items in two different locations we will adopt an approach of keeping an internal BehaviorSubject which we can derive multiple observables from, in order to create our filtered subsets.
dependencies
- Angular Material Components source
to add angular material run ng add @angular/material
in your angular project root. When prompted to add animations select Yes
Modify your module: default is app.module
Before you can utilize the CDK drag and drop directive, you must add the DragDropModule to your imports.
@NgModule({
declarations: [
...
],
imports: [
...
DragDropModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Create a component
controller
@Component({
selector: 'drag-drop-demo',
templateUrl: './drag-drop-demo.component.html',
styleUrls: ['./drag-drop-demo.component.scss']
})
export class DragDropDemoComponent implements OnInit, OnChanges, OnDestroy {
// utilize behaviorSubject so we always get the latest input in our observables regardless of lifecycle timing.
private internal!: BehaviorSubject<number[]>;
@Input() listItems!: number[];
conditionAppliesList!: number[];
conditionDoesNotApplyList!: number[];
subscriptions: Subscription;
constructor() {
this.internal = new BehaviorSubject<number[]>([]);
this.subscriptions = new Subscription();
}
ngOnInit(): void {
// setup two distinct observables that apply some filter condition to our list.
this.subscriptions.add(
this.internal.asObservable()
.pipe(map(items => items.filter(number => number % 2 == 0))).subscribe(numbers => {
this.conditionAppliesList = numbers;
})
);
this.subscriptions.add(
this.internal.asObservable()
.pipe(map(items => items.filter(number => number % 2 != 0))).subscribe(numbers => {
this.conditionDoesNotApplyList = numbers;
})
);
}
ngOnChanges(changes: SimpleChanges): void {
// when listItems are detected in our input, emit the values in the internal BehaviorSubject
if ('listItems' in changes) {
// emit next value
this.internal.next(this.listItems);
}
}
ngOnDestroy() {
// cleanup the subscriptions.
this.subscriptions.unsubscribe();
}
// cdkHandler.
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.conditionAppliesList, event.previousIndex, event.currentIndex);
}
}
template
<h2>Drag and drop</h2>
<div class="list-outlet">
<h3>Draggable</h3>
<div class="list-container" cdkDropList (cdkDropListDropped)="drop($event)">
<div class="list-item" *ngFor="let num of conditionAppliesList" cdkDrag>
{{num}}
</div>
</div>
<h3>Non-Draggable</h3>
<div class="list-container">
<div class="list-item" *ngFor="let num of conditionDoesNotApplyList">
{{num}}
</div>
</div>
</div>
See demonstration on StackBlitz