• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 23353730325

20 Mar 2026 05:03PM UTC coverage: 9.784% (-79.5%) from 89.264%
23353730325

Pull #17069

github

web-flow
Merge cfa7e86d1 into a4dc50177
Pull Request #17069: fix(IgxGrid): Do not apply width constraint to groups.

921 of 16963 branches covered (5.43%)

Branch coverage included in aggregate %.

1 of 3 new or added lines in 1 file covered. (33.33%)

25213 existing lines in 340 files now uncovered.

3842 of 31721 relevant lines covered (12.11%)

6.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.72
/projects/igniteui-angular/chips/src/chips/chips-area.component.ts
1
import { Component, ContentChildren, ChangeDetectorRef, EventEmitter, HostBinding, Input, IterableDiffer, IterableDiffers, Output, QueryList, DoCheck, AfterViewInit, OnDestroy, ElementRef, inject } from '@angular/core';
2
import {
3
    IgxChipComponent,
4
    IChipSelectEventArgs,
5
    IChipKeyDownEventArgs,
6
    IChipEnterDragAreaEventArgs,
7
    IBaseChipEventArgs
8
} from './chip.component';
9
import { IDropBaseEventArgs, IDragBaseEventArgs } from 'igniteui-angular/directives';
10
import { takeUntil } from 'rxjs/operators';
11
import { Subject } from 'rxjs';
12
import { rem } from 'igniteui-angular/core';
13

14
export interface IBaseChipsAreaEventArgs {
15
    originalEvent: IDragBaseEventArgs | IDropBaseEventArgs | KeyboardEvent | MouseEvent | TouchEvent;
16
    owner: IgxChipsAreaComponent;
17
}
18

19
export interface IChipsAreaReorderEventArgs extends IBaseChipsAreaEventArgs {
20
    chipsArray: IgxChipComponent[];
21
}
22

23
export interface IChipsAreaSelectEventArgs extends IBaseChipsAreaEventArgs {
24
    newSelection: IgxChipComponent[];
25
}
26

27
/**
28
 * The chip area allows you to perform more complex scenarios with chips that require interaction,
29
 * like dragging, selection, navigation, etc.
30
 *
31
 * @igxModule IgxChipsModule
32
 *
33
 * @igxTheme igx-chip-theme
34
 *
35
 * @igxKeywords chip area, chip
36
 *
37
 * @igxGroup display
38
 *
39
 * @example
40
 * ```html
41
 * <igx-chips-area>
42
 *    <igx-chip *ngFor="let chip of chipList" [id]="chip.id">
43
 *        <span>{{chip.text}}</span>
44
 *    </igx-chip>
45
 * </igx-chips-area>
46
 * ```
47
 */
48
@Component({
49
    selector: 'igx-chips-area',
50
    templateUrl: 'chips-area.component.html',
51
    standalone: true
52
})
53
export class IgxChipsAreaComponent implements DoCheck, AfterViewInit, OnDestroy {
3✔
UNCOV
54
     public cdr = inject(ChangeDetectorRef);
×
UNCOV
55
     public element = inject(ElementRef);
×
UNCOV
56
     private _iterableDiffers = inject(IterableDiffers);
×
57

58

59
    /**
60
     * Returns the `role` attribute of the chips area.
61
     *
62
     * @example
63
     * ```typescript
64
     * let chipsAreaRole = this.chipsArea.role;
65
     * ```
66
     */
67
     @HostBinding('attr.role')
UNCOV
68
     public role = 'listbox';
×
69

70
    /**
71
     * Returns the `aria-label` attribute of the chips area.
72
     *
73
     * @example
74
     * ```typescript
75
     * let ariaLabel = this.chipsArea.ariaLabel;
76
     * ```
77
     *
78
     */
79
     @HostBinding('attr.aria-label')
UNCOV
80
     public ariaLabel = 'chip area';
×
81

82
    /**
83
     * Sets the width of the `IgxChipsAreaComponent`.
84
     *
85
     * @example
86
     * ```html
87
     * <igx-chips-area #chipsArea [width]="300" [height]="10" (onReorder)="chipsOrderChanged($event)"></igx-chips-area>
88
     * ```
89
     */
90
    @Input()
91
    public width: number;
92

93
    /** @hidden @internal */
94
    @HostBinding('style.width.rem')
95
    public get _widthToRem() {
UNCOV
96
        return rem(this.width);
×
97
    }
98

99
    /**
100
     * Sets the height of the `IgxChipsAreaComponent`.
101
     *
102
     * @example
103
     * ```html
104
     * <igx-chips-area #chipsArea [width]="300" [height]="10" (onReorder)="chipsOrderChanged($event)"></igx-chips-area>
105
     * ```
106
     */
107
    @Input()
108
    public height: number;
109

110
    /** @hidden @internal */
111
    @HostBinding('style.height.rem')
112
    public get _heightToRem() {
UNCOV
113
        return rem(this.height);
×
114
    }
115

116
    /**
117
     * Emits an event when `IgxChipComponent`s in the `IgxChipsAreaComponent` should be reordered.
118
     * Returns an array of `IgxChipComponent`s.
119
     *
120
     * @example
121
     * ```html
122
     * <igx-chips-area #chipsArea [width]="'300'" [height]="'10'" (onReorder)="changedOrder($event)"></igx-chips-area>
123
     * ```
124
     */
125
    @Output()
UNCOV
126
    public reorder = new EventEmitter<IChipsAreaReorderEventArgs>();
×
127

128
    /**
129
     * Emits an event when an `IgxChipComponent` in the `IgxChipsAreaComponent` is selected/deselected.
130
     * Fired after the chips area is initialized if there are initially selected chips as well.
131
     * Returns an array of selected `IgxChipComponent`s and the `IgxChipAreaComponent`.
132
     *
133
     * @example
134
     * ```html
135
     * <igx-chips-area #chipsArea [width]="'300'" [height]="'10'" (selectionChange)="selection($event)"></igx-chips-area>
136
     * ```
137
     */
138
    @Output()
UNCOV
139
    public selectionChange = new EventEmitter<IChipsAreaSelectEventArgs>();
×
140

141
    /**
142
     * Emits an event when an `IgxChipComponent` in the `IgxChipsAreaComponent` is moved.
143
     *
144
     * @example
145
     * ```html
146
     * <igx-chips-area #chipsArea [width]="'300'" [height]="'10'" (moveStart)="moveStart($event)"></igx-chips-area>
147
     * ```
148
     */
149
    @Output()
UNCOV
150
    public moveStart = new EventEmitter<IBaseChipsAreaEventArgs>();
×
151

152
    /**
153
     * Emits an event after an `IgxChipComponent` in the `IgxChipsAreaComponent` is moved.
154
     *
155
     * @example
156
     * ```html
157
     * <igx-chips-area #chipsArea [width]="'300'" [height]="'10'" (moveEnd)="moveEnd($event)"></igx-chips-area>
158
     * ```
159
     */
160
    @Output()
UNCOV
161
    public moveEnd = new EventEmitter<IBaseChipsAreaEventArgs>();
×
162

163
    /**
164
     * Holds the `IgxChipComponent` in the `IgxChipsAreaComponent`.
165
     *
166
     * @example
167
     * ```typescript
168
     * ngAfterViewInit(){
169
     *    let chips = this.chipsArea.chipsList;
170
     * }
171
     * ```
172
     */
173
    @ContentChildren(IgxChipComponent, { descendants: true })
174
    public chipsList: QueryList<IgxChipComponent>;
175

UNCOV
176
    protected destroy$ = new Subject<boolean>();
×
177

178
    @HostBinding('class')
UNCOV
179
    protected hostClass = 'igx-chip-area';
×
180

181
    private modifiedChipsArray: IgxChipComponent[];
UNCOV
182
    private _differ: IterableDiffer<IgxChipComponent> | null = null;
×
183

184
    constructor() {
UNCOV
185
        this._differ = this._iterableDiffers.find([]).create(null);
×
186
    }
187

188
    /**
189
     * @hidden
190
     * @internal
191
     */
192
    public ngAfterViewInit() {
193
        // If we have initially selected chips through their inputs, we need to get them, because we cannot listen to their events yet.
UNCOV
194
        if (this.chipsList.length) {
×
UNCOV
195
            const selectedChips = this.chipsList.filter((item: IgxChipComponent) => item.selected);
×
UNCOV
196
            if (selectedChips.length) {
×
UNCOV
197
                this.selectionChange.emit({
×
198
                    originalEvent: null,
199
                    newSelection: selectedChips,
200
                    owner: this
201
                });
202
            }
203
        }
204
    }
205

206
    /**
207
     * @hidden
208
     * @internal
209
     */
210
    public ngDoCheck(): void {
UNCOV
211
        if (this.chipsList) {
×
UNCOV
212
            const changes = this._differ.diff(this.chipsList.toArray());
×
UNCOV
213
            if (changes) {
×
UNCOV
214
                changes.forEachAddedItem((addedChip) => {
×
UNCOV
215
                    addedChip.item.moveStart.pipe(takeUntil(addedChip.item.destroy$)).subscribe((args) => {
×
UNCOV
216
                        this.onChipMoveStart(args);
×
217
                    });
UNCOV
218
                    addedChip.item.moveEnd.pipe(takeUntil(addedChip.item.destroy$)).subscribe((args) => {
×
UNCOV
219
                        this.onChipMoveEnd(args);
×
220
                    });
UNCOV
221
                    addedChip.item.dragEnter.pipe(takeUntil(addedChip.item.destroy$)).subscribe((args) => {
×
UNCOV
222
                        this.onChipDragEnter(args);
×
223
                    });
UNCOV
224
                    addedChip.item.keyDown.pipe(takeUntil(addedChip.item.destroy$)).subscribe((args) => {
×
UNCOV
225
                        this.onChipKeyDown(args);
×
226
                    });
UNCOV
227
                    if (addedChip.item.selectable) {
×
UNCOV
228
                        addedChip.item.selectedChanging.pipe(takeUntil(addedChip.item.destroy$)).subscribe((args) => {
×
UNCOV
229
                            this.onChipSelectionChange(args);
×
230
                        });
231
                    }
232
                });
UNCOV
233
                this.modifiedChipsArray = this.chipsList.toArray();
×
234
            }
235
        }
236
    }
237

238
    /**
239
     * @hidden
240
     * @internal
241
     */
242
    public ngOnDestroy(): void {
UNCOV
243
        this.destroy$.next(true);
×
UNCOV
244
        this.destroy$.complete();
×
245
    }
246

247
    /**
248
     * @hidden
249
     * @internal
250
     */
251
    protected onChipKeyDown(event: IChipKeyDownEventArgs) {
UNCOV
252
        let orderChanged = false;
×
UNCOV
253
        const chipsArray = this.chipsList.toArray();
×
UNCOV
254
        const dragChipIndex = chipsArray.findIndex((el) => el === event.owner);
×
UNCOV
255
        if (event.originalEvent.shiftKey === true) {
×
UNCOV
256
            if (event.originalEvent.key === 'ArrowLeft' || event.originalEvent.key === 'Left') {
×
UNCOV
257
                orderChanged = this.positionChipAtIndex(dragChipIndex, dragChipIndex - 1, false, event.originalEvent);
×
UNCOV
258
                if (orderChanged) {
×
UNCOV
259
                    setTimeout(() => {
×
UNCOV
260
                        this.chipsList.get(dragChipIndex - 1).nativeElement.focus();
×
261
                    });
262
                }
UNCOV
263
            } else if (event.originalEvent.key === 'ArrowRight' || event.originalEvent.key === 'Right') {
×
UNCOV
264
                orderChanged = this.positionChipAtIndex(dragChipIndex, dragChipIndex + 1, true, event.originalEvent);
×
265
            }
266
        } else {
UNCOV
267
            if ((event.originalEvent.key === 'ArrowLeft' || event.originalEvent.key === 'Left') && dragChipIndex > 0) {
×
UNCOV
268
                chipsArray[dragChipIndex - 1].nativeElement.focus();
×
UNCOV
269
            } else if ((event.originalEvent.key === 'ArrowRight' || event.originalEvent.key === 'Right') &&
×
270
                dragChipIndex < chipsArray.length - 1) {
UNCOV
271
                chipsArray[dragChipIndex + 1].nativeElement.focus();
×
272
            }
273
        }
274
    }
275

276
    /**
277
     * @hidden
278
     * @internal
279
     */
280
    protected onChipMoveStart(event: IBaseChipEventArgs) {
UNCOV
281
        this.moveStart.emit({
×
282
            originalEvent: event.originalEvent,
283
            owner: this
284
        });
285
    }
286

287
    /**
288
     * @hidden
289
     * @internal
290
     */
291
    protected onChipMoveEnd(event: IBaseChipEventArgs) {
UNCOV
292
        this.moveEnd.emit({
×
293
            originalEvent: event.originalEvent,
294
            owner: this
295
        });
296
    }
297

298
    /**
299
     * @hidden
300
     * @internal
301
     */
302
    protected onChipDragEnter(event: IChipEnterDragAreaEventArgs) {
UNCOV
303
        const dropChipIndex = this.chipsList.toArray().findIndex((el) => el === event.owner);
×
UNCOV
304
        const dragChipIndex = this.chipsList.toArray().findIndex((el) => el === event.dragChip);
×
UNCOV
305
        if (dragChipIndex < dropChipIndex) {
×
306
            // from the left to right
UNCOV
307
            this.positionChipAtIndex(dragChipIndex, dropChipIndex, true, event.originalEvent);
×
308
        } else {
309
            // from the right to left
UNCOV
310
            this.positionChipAtIndex(dragChipIndex, dropChipIndex, false, event.originalEvent);
×
311
        }
312
    }
313

314
    /**
315
     * @hidden
316
     * @internal
317
     */
318
    protected positionChipAtIndex(chipIndex, targetIndex, shiftRestLeft, originalEvent) {
UNCOV
319
        if (chipIndex < 0 || this.chipsList.length <= chipIndex ||
×
320
            targetIndex < 0 || this.chipsList.length <= targetIndex) {
UNCOV
321
            return false;
×
322
        }
323

UNCOV
324
        const chipsArray = this.chipsList.toArray();
×
UNCOV
325
        const result: IgxChipComponent[] = [];
×
UNCOV
326
        for (let i = 0; i < chipsArray.length; i++) {
×
UNCOV
327
            if (shiftRestLeft) {
×
UNCOV
328
                if (chipIndex <= i && i < targetIndex) {
×
UNCOV
329
                    result.push(chipsArray[i + 1]);
×
UNCOV
330
                } else if (i === targetIndex) {
×
UNCOV
331
                    result.push(chipsArray[chipIndex]);
×
332
                } else {
UNCOV
333
                    result.push(chipsArray[i]);
×
334
                }
335
            } else {
UNCOV
336
                if (targetIndex < i && i <= chipIndex) {
×
UNCOV
337
                    result.push(chipsArray[i - 1]);
×
UNCOV
338
                } else if (i === targetIndex) {
×
UNCOV
339
                    result.push(chipsArray[chipIndex]);
×
340
                } else {
UNCOV
341
                    result.push(chipsArray[i]);
×
342
                }
343
            }
344
        }
UNCOV
345
        this.modifiedChipsArray = result;
×
346

UNCOV
347
        const eventData: IChipsAreaReorderEventArgs = {
×
348
            chipsArray: this.modifiedChipsArray,
349
            originalEvent,
350
            owner: this
351
        };
UNCOV
352
        this.reorder.emit(eventData);
×
UNCOV
353
        return true;
×
354
    }
355

356
    /**
357
     * @hidden
358
     * @internal
359
     */
360
    protected onChipSelectionChange(event: IChipSelectEventArgs) {
UNCOV
361
        let selectedChips = this.chipsList.filter((chip) => chip.selected);
×
UNCOV
362
        if (event.selected && !selectedChips.includes(event.owner)) {
×
UNCOV
363
            selectedChips.push(event.owner);
×
UNCOV
364
        } else if (!event.selected && selectedChips.includes(event.owner)) {
×
UNCOV
365
            selectedChips = selectedChips.filter((chip) => chip.id !== event.owner.id);
×
366
        }
UNCOV
367
        this.selectionChange.emit({
×
368
            originalEvent: event.originalEvent,
369
            newSelection: selectedChips,
370
            owner: this
371
        });
372
    }
373
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc