After looking over some purely decorative CSS in the Angular Signals code lab sample application, I dug around elsewhere in the source code for interesting things to learn. The next item that caught my attention was the “keyboard” where we drag-and-dropped letters to create our decoder. How was this done?
Inside the HTML template code, I found an attribute
cdkDropListGroup on the keyboard container. A web search pointed me to the Angular CDK (Control Development Kit.) Angular CDK is a library that packages many common web app behaviors we can use in our own custom controls, one of them being drag-and-drop as used in the Angular Signals sample app. The CDK is apparently under the umbrella of Angular Material, which has a set of fully implemented app controls implemented to the Material Design specification. Many of them use the CDK for their own implementation.
Drag-and-drop behavior in Angular CDK is very flexible and has many options for configuring behavior. Such flexibility and options unfortunately also meant it’s easy for a beginner to get lost. I’m thankful I have the Angular Signals code lab cipher app. It lets me look over a very specific simple use of CDK drag-and-drop.
Here’s an excerpt of the HTML template for the cipher keyboard in file
cipher.ts, stripped of everything unrelated to drag-and-drop.
<div class="cipher-wrapper" cdkDropListGroup> <div class="key-container"> <letter-key *ngFor="let l of this.cipher.alphabet" cdkDropList cdkDropListSortingDisabled [cdkDropListData]="l"/> </div> <div class="guess-container" cdkDropList cdkDropListSortingDisabled> <letter-guess *ngFor="let l of this.cipher.unsolvedAlphabet()" cdkDrag [cdkDragData]="l" (cdkDragDropped)="drop($event)"> <div class="placeholder" *cdkDragPlaceholder></div> </letter-guess> </div> </div>
It has two containers, one for a list of custom control
letter-key and and another for a list of
letter-guess. Drag-and-drop is all encapsulated here in
cipher.ts, there’s nothing in either of those two controls concerning drag-and-drop.
Uniting these two containers is a div with
cdkDropListGroup which associates all child
cdkDropList elements together. This allows us to drag individual
letter-guess (tagged with
cdkDrag) from one
cdkDropList onto the sibling
letter-key. These properties are enough to let Angular CDK know how to respond to pointer input events to manipulate these elements. All the app has to do is register a
cdkDragDropped listener for when a
cdkDrag element is dropped into a
I poked around the code looking for how a
letter-guess sits in the
key-container after it has been dropped into the right location. The answer is: it doesn’t, that’s just an illusion. When a letter is dropped into the correct location, it is removed from the list returned by
this.cipher.unsolvedalphabet(). Meaning that particular
letter-guess I had been dragging disappears. The
letter-key I had dragged it onto, however, will pick up a new CSS class and change its appearance to look as if the
letter-guess stayed in that location.
I had to spend some time flipping between looking at source code and looking at CDK drag-and-drop API documentation. But once I made that time investment, I could understand how this app utilized the library. Once understood, I’m impressed at how little work is required in an Angular app to pick up very complex behavior from Angular CDK.
I look forward to leveraging this capability in my own projects in the future. Before that, though, I can try using Angular signals in my Compass practice app.