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

IgniteUI / igniteui-angular / 28013325390

23 Jun 2026 08:34AM UTC coverage: 90.139% (-0.02%) from 90.154%
28013325390

Pull #17324

github

web-flow
Merge 690ff31c5 into 01244911c
Pull Request #17324: fix(skills): omit column widths by default in generated grid code

14880 of 17339 branches covered (85.82%)

Branch coverage included in aggregate %.

29947 of 32392 relevant lines covered (92.45%)

34656.81 hits per line

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

92.82
/projects/igniteui-angular/tree/src/tree/tree-node/tree-node.component.ts
1
import { ChangeDetectorRef, Component, ContentChildren, Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, OnDestroy, OnInit, Output, QueryList, TemplateRef, ViewChild, booleanAttribute, inject, ChangeDetectionStrategy } from '@angular/core';
2
import { takeUntil } from 'rxjs/operators';
3
import {
4
    IgxTree,
5
    IgxTreeNode,
6
    IgxTreeSelectionType,
7
    IGX_TREE_COMPONENT,
8
    IGX_TREE_NODE_COMPONENT,
9
    ITreeNodeTogglingEventArgs
10
} from '../common';
11
import { IgxTreeNavigationService } from '../tree-navigation.service';
12
import { IgxTreeSelectionService } from '../tree-selection.service';
13
import { IgxTreeService } from '../tree.service';
14
import { NgTemplateOutlet, NgClass } from '@angular/common';
15
import { IgxIconComponent } from 'igniteui-angular/icon';
16
import { IgxCheckboxComponent } from 'igniteui-angular/checkbox';
17
import { IgxCircularProgressBarComponent } from 'igniteui-angular/progressbar';
18
import { ToggleAnimationPlayer, ToggleAnimationSettings } from 'igniteui-angular/expansion-panel';
19
import { getCurrentResourceStrings, onResourceChangeHandle, ITreeResourceStrings, TreeResourceStringsEN } from 'igniteui-angular/core';
20

21
// TODO: Implement aria functionality
22
/**
23
 * @hidden @internal
24
 * Used for links (`a` tags) in the body of an `igx-tree-node`. Handles aria and event dispatch.
25
 */
26
@Directive({
27
    selector: `[igxTreeNodeLink]`,
28
    standalone: true
29
})
30
export class IgxTreeNodeLinkDirective implements OnDestroy {
3✔
31
    private node = inject<IgxTreeNode<any>>(IGX_TREE_NODE_COMPONENT, { optional: true });
30✔
32
    private navService = inject(IgxTreeNavigationService);
30✔
33
    public elementRef = inject(ElementRef);
30✔
34

35

36
    @HostBinding('attr.role')
37
    public role = 'treeitem';
30✔
38

39
    /**
40
     * The node's parent. Should be used only when the link is defined
41
     * in `<ng-template>` tag outside of its parent, as Angular DI will not properly provide a reference
42
     *
43
     * ```html
44
     * <igx-tree>
45
     *     <igx-tree-node #myNode *ngFor="let node of data" [data]="node">
46
     *         <ng-template *ngTemplateOutlet="nodeTemplate; context: { $implicit: data, parentNode: myNode }">
47
     *         </ng-template>
48
     *     </igx-tree-node>
49
     *     ...
50
     *     <!-- node template is defined under tree to access related services -->
51
     *     <ng-template #nodeTemplate let-data let-node="parentNode">
52
     *         <a [igxTreeNodeLink]="node">{{ data.label }}</a>
53
     *     </ng-template>
54
     * </igx-tree>
55
     * ```
56
     */
57
    @Input('igxTreeNodeLink')
58
    public set parentNode(val: any) {
59
        if (val) {
30✔
60
            this._parentNode = val;
15✔
61
            (this._parentNode as any).addLinkChild(this);
15✔
62
        }
63
    }
64

65
    public get parentNode(): any {
66
        return this._parentNode;
113✔
67
    }
68

69
    /** A pointer to the parent node */
70
    private get target(): IgxTreeNode<any> {
71
        return this.node || this.parentNode;
226✔
72
    }
73

74
    private _parentNode: IgxTreeNode<any> = null;
30✔
75

76
    /** @hidden @internal */
77
    @HostBinding('attr.tabindex')
78
    public get tabIndex(): number {
79
        return this.navService.focusedNode === this.target ? (this.target?.disabled ? -1 : 0) : -1;
181!
80
    }
81

82
    /**
83
     * @hidden @internal
84
     * Clear the node's focused state
85
     */
86
    @HostListener('blur')
87
    public handleBlur() {
88
        this.target.isFocused = false;
×
89
    }
90

91
    /**
92
     * @hidden @internal
93
     * Set the node as focused
94
     */
95
    @HostListener('focus')
96
    public handleFocus() {
97
        if (this.target && !this.target.disabled) {
2✔
98
            if (this.navService.focusedNode !== this.target) {
2!
99
                this.navService.focusedNode = this.target;
×
100
            }
101
            this.target.isFocused = true;
2✔
102
        }
103
    }
104

105
    public ngOnDestroy() {
106
        this.target.removeLinkChild(this);
30✔
107
    }
108
}
109

110
/**
111
 *
112
 * The tree node component represents a child node of the tree component or another tree node.
113
 * Usage:
114
 *
115
 * ```html
116
 *  <igx-tree>
117
 *  ...
118
 *    <igx-tree-node [data]="data" [selected]="service.isNodeSelected(data.Key)" [expanded]="service.isNodeExpanded(data.Key)">
119
 *      {{ data.FirstName }} {{ data.LastName }}
120
 *    </igx-tree-node>
121
 *  ...
122
 *  </igx-tree>
123
 * ```
124
 */
125
@Component({
126
    selector: 'igx-tree-node',
127
    templateUrl: 'tree-node.component.html',
128
    providers: [
129
        { provide: IGX_TREE_NODE_COMPONENT, useExisting: IgxTreeNodeComponent }
130
    ],
131
    changeDetection: ChangeDetectionStrategy.Eager,
132
    imports: [NgTemplateOutlet, IgxIconComponent, IgxCheckboxComponent, NgClass, IgxCircularProgressBarComponent]
133
})
134
export class IgxTreeNodeComponent<T> extends ToggleAnimationPlayer implements IgxTreeNode<T>, OnInit, OnDestroy {
3✔
135
    public tree = inject<IgxTree>(IGX_TREE_COMPONENT);
3,540✔
136
    protected selectionService = inject(IgxTreeSelectionService);
3,540✔
137
    protected treeService = inject(IgxTreeService);
3,540✔
138
    protected navService = inject(IgxTreeNavigationService);
3,540✔
139
    protected cdr = inject(ChangeDetectorRef);
3,540✔
140
    private element = inject<ElementRef<HTMLElement>>(ElementRef);
3,540✔
141
    public parentNode = inject<IgxTreeNode<any>>(IGX_TREE_NODE_COMPONENT, { optional: true, skipSelf: true });
3,540✔
142

143
    /**
144
     * The data entry that the node is visualizing.
145
     *
146
     * @remarks
147
     * Required for searching through nodes.
148
     *
149
     * @example
150
     * ```html
151
     *  <igx-tree>
152
     *  ...
153
     *    <igx-tree-node [data]="data">
154
     *      {{ data.FirstName }} {{ data.LastName }}
155
     *    </igx-tree-node>
156
     *  ...
157
     *  </igx-tree>
158
     * ```
159
     */
160
    @Input()
161
    public data: T;
162

163
    /**
164
     * To be used for load-on-demand scenarios in order to specify whether the node is loading data.
165
     *
166
     * @remarks
167
     * Loading nodes do not render children.
168
     */
169
    @Input({ transform: booleanAttribute })
170
    public loading = false;
3,540✔
171

172
    // TO DO: return different tab index depending on anchor child
173
    /** @hidden @internal */
174
    public set tabIndex(val: number) {
175
        this._tabIndex = val;
73✔
176
    }
177

178
    /** @hidden @internal */
179
    public get tabIndex(): number {
180
        if (this.disabled) {
38,249✔
181
            return -1;
736✔
182
        }
183
        if (this._tabIndex === null) {
37,513✔
184
            if (this.navService.focusedNode === null) {
37,157✔
185
                return this.hasLinkChildren ? -1 : 0;
32,630✔
186
            }
187
            return -1;
4,527✔
188
        }
189
        return this.hasLinkChildren ? -1 : this._tabIndex;
356✔
190
    }
191

192
    /** @hidden @internal */
193
    public override get animationSettings(): ToggleAnimationSettings {
194
        return this.tree.animationSettings;
25✔
195
    }
196

197
    /**
198
     * Gets/Sets the resource strings.
199
     *
200
     * @remarks
201
     * Uses EN resources by default.
202
     */
203
    @Input()
204
    public set resourceStrings(value: ITreeResourceStrings) {
205
        this._resourceStrings = Object.assign({}, this._resourceStrings, value);
×
206
    }
207

208
    /**
209
     * An accessor that returns the resource strings.
210
     */
211
    public get resourceStrings(): ITreeResourceStrings {
212
        return this._resourceStrings || this._defaultResourceStrings;
21,887✔
213
    }
214

215
    /**
216
     * Gets/Sets the active state of the node
217
     *
218
     * @param value: boolean
219
     */
220
    @Input({ transform: booleanAttribute })
221
    public set active(value: boolean) {
222
        if (value) {
247✔
223
            this.navService.activeNode = this;
175✔
224
            this.tree.activeNodeBindingChange.emit(this);
175✔
225
        }
226
    }
227

228
    public get active(): boolean {
229
        return this.navService.activeNode === this;
38,250✔
230
    }
231

232
    /**
233
     * Emitted when the node's `selected` property changes.
234
     *
235
     * ```html
236
     * <igx-tree>
237
     *      <igx-tree-node *ngFor="let node of data" [data]="node" [(selected)]="node.selected">
238
     *      </igx-tree-node>
239
     * </igx-tree>
240
     * ```
241
     *
242
     * ```typescript
243
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
244
     * node.selectedChange.pipe(takeUntil(this.destroy$)).subscribe((e: boolean) => console.log("Node selection changed to ", e))
245
     * ```
246
     */
247
    @Output()
248
    public selectedChange = new EventEmitter<boolean>();
3,540✔
249

250
    /**
251
     * Emitted when the node's `expanded` property changes.
252
     *
253
     * ```html
254
     * <igx-tree>
255
     *      <igx-tree-node *ngFor="let node of data" [data]="node" [(expanded)]="node.expanded">
256
     *      </igx-tree-node>
257
     * </igx-tree>
258
     * ```
259
     *
260
     * ```typescript
261
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
262
     * node.expandedChange.pipe(takeUntil(this.destroy$)).subscribe((e: boolean) => console.log("Node expansion state changed to ", e))
263
     * ```
264
     */
265
    @Output()
266
    public expandedChange = new EventEmitter<boolean>();
3,540✔
267

268
    /** @hidden @internal */
269
    public get focused() {
270
        return this.isFocused &&
38,249✔
271
            this.navService.focusedNode === this;
272
    }
273

274
    /**
275
     * Retrieves the full path to the node incuding itself
276
     *
277
     * ```typescript
278
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
279
     * const path: IgxTreeNode<any>[] = node.path;
280
     * ```
281
     */
282
    public get path(): IgxTreeNode<any>[] {
283
        return this.parentNode?.path ? [...this.parentNode.path, this] : [this];
762✔
284
    }
285

286
    // TODO: bind to disabled state when node is dragged
287
    /**
288
     * Gets/Sets the disabled state of the node
289
     *
290
     * @param value: boolean
291
     */
292
    @Input({ transform: booleanAttribute })
293
    @HostBinding('class.igx-tree-node--disabled')
294
    public get disabled(): boolean {
295
        return this._disabled;
122,368✔
296
    }
297

298
    public set disabled(value: boolean) {
299
        if (value !== this._disabled) {
398✔
300
            this._disabled = value;
83✔
301
            this.tree.disabledChange.emit(this);
83✔
302
        }
303
    }
304

305
    /** @hidden @internal */
306
    @HostBinding('class.igx-tree-node')
307
    public cssClass = 'igx-tree-node';
3,540✔
308

309
    /** @hidden @internal */
310
    @HostBinding('attr.role')
311
    public get role() {
312
        return this.hasLinkChildren ? 'none' : 'treeitem';
76,475✔
313
    }
314

315
    /** @hidden @internal */
316
    @ContentChildren(IgxTreeNodeLinkDirective, { read: ElementRef })
317
    public linkChildren: QueryList<ElementRef>;
318

319
    /** @hidden @internal */
320
    @ContentChildren(IGX_TREE_NODE_COMPONENT, { read: IGX_TREE_NODE_COMPONENT })
321
    public _children: QueryList<IgxTreeNode<any>>;
322

323
    /** @hidden @internal */
324
    @ContentChildren(IGX_TREE_NODE_COMPONENT, { read: IGX_TREE_NODE_COMPONENT, descendants: true })
325
    public allChildren: QueryList<IgxTreeNode<any>>;
326

327
    /**
328
     * Return the child nodes of the node (if any)
329
     *
330
     * @remarks
331
     * Returns `null` if node does not have children
332
     *
333
     * @example
334
     * ```typescript
335
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
336
     * const children: IgxTreeNode<any>[] = node.children;
337
     * ```
338
     */
339
    public get children(): IgxTreeNode<any>[] {
340
        return this._children?.length ? this._children.toArray() : null;
×
341
    }
342

343
    // TODO: will be used in Drag and Drop implementation
344
    /** @hidden @internal */
345
    @ViewChild('ghostTemplate', { read: ElementRef })
346
    public header: ElementRef;
347

348
    @ViewChild('defaultIndicator', { read: TemplateRef, static: true })
349
    private _defaultExpandIndicatorTemplate: TemplateRef<any>;
350

351
    @ViewChild('childrenContainer', { read: ElementRef })
352
    private childrenContainer: ElementRef;
353

354
    private get hasLinkChildren(): boolean {
355
        return this.linkChildren?.length > 0 || this.registeredChildren?.length > 0;
109,461✔
356
    }
357

358
    /** @hidden @internal */
359
    public isFocused: boolean;
360

361
    /** @hidden @internal */
362
    public registeredChildren: IgxTreeNodeLinkDirective[] = [];
3,540✔
363

364
    private _resourceStrings: ITreeResourceStrings = null;
3,540✔
365
    private _defaultResourceStrings = getCurrentResourceStrings(TreeResourceStringsEN);
3,540✔
366
    private _tabIndex = null;
3,540✔
367
    private _disabled = false;
3,540✔
368

369
    constructor() {
370
        super();
3,540✔
371
        onResourceChangeHandle(this.destroy$, () => {
3,540✔
372
            this._defaultResourceStrings = getCurrentResourceStrings(TreeResourceStringsEN, false);
×
373
        }, this);
374
    }
375

376
    /**
377
     * @hidden @internal
378
     */
379
    public get showSelectors() {
380
        return this.tree.selection !== IgxTreeSelectionType.None;
38,249✔
381
    }
382

383
    /**
384
     * @hidden @internal
385
     */
386
    public get indeterminate(): boolean {
387
        return this.selectionService.isNodeIndeterminate(this);
7,613✔
388
    }
389

390
    /** The depth of the node, relative to the root
391
     *
392
     * ```html
393
     * <igx-tree>
394
     *  ...
395
     *  <igx-tree-node #node>
396
     *      My level is {{ node.level }}
397
     *  </igx-tree-node>
398
     * </igx-tree>
399
     * ```
400
     *
401
     * ```typescript
402
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[12])[0];
403
     * const level: number = node.level;
404
     * ```
405
     */
406
    public get level(): number {
407
        return this.parentNode ? this.parentNode.level + 1 : 0;
195,120✔
408
    }
409

410
    /** Get/set whether the node is selected. Supporst two-way binding.
411
     *
412
     * ```html
413
     * <igx-tree>
414
     *  ...
415
     *  <igx-tree-node *ngFor="let node of data" [(selected)]="node.selected">
416
     *      {{ node.label }}
417
     *  </igx-tree-node>
418
     * </igx-tree>
419
     * ```
420
     *
421
     * ```typescript
422
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
423
     * const selected = node.selected;
424
     * node.selected = true;
425
     * ```
426
     */
427
    @Input({ transform: booleanAttribute })
428
    public get selected(): boolean {
429
        return this.selectionService.isNodeSelected(this);
46,582✔
430
    }
431

432
    public set selected(val: boolean) {
433
        if (!(this.tree?.nodes && this.tree.nodes.find((e) => e === this)) && val) {
5,496✔
434
            this.tree.forceSelect.push(this);
357✔
435
            return;
357✔
436
        }
437
        if (val && !this.selectionService.isNodeSelected(this)) {
880✔
438
            this.selectionService.selectNodesWithNoEvent([this]);
98✔
439
        }
440
        if (!val && this.selectionService.isNodeSelected(this)) {
880✔
441
            this.selectionService.deselectNodesWithNoEvent([this]);
9✔
442
        }
443
    }
444

445
    /** Get/set whether the node is expanded
446
     *
447
     * ```html
448
     * <igx-tree>
449
     *  ...
450
     *  <igx-tree-node *ngFor="let node of data" [expanded]="node.name === this.expandedNode">
451
     *      {{ node.label }}
452
     *  </igx-tree-node>
453
     * </igx-tree>
454
     * ```
455
     *
456
     * ```typescript
457
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
458
     * const expanded = node.expanded;
459
     * node.expanded = true;
460
     * ```
461
     */
462
    @Input({ transform: booleanAttribute })
463
    public get expanded() {
464
        return this.treeService.isExpanded(this);
121,282✔
465
    }
466

467
    public set expanded(val: boolean) {
468
        if (val) {
1,668✔
469
            this.treeService.expand(this, false);
76✔
470
        } else {
471
            this.treeService.collapse(this);
1,592✔
472
        }
473
    }
474

475
    /** @hidden @internal */
476
    public get expandIndicatorTemplate(): TemplateRef<any> {
477
        return this.tree?.expandIndicator || this._defaultExpandIndicatorTemplate;
38,249✔
478
    }
479

480
    /**
481
     * The native DOM element representing the node. Could be null in certain environments.
482
     *
483
     * ```typescript
484
     * // get the nativeElement of the second node
485
     * const node: IgxTreeNode = this.tree.nodes.first();
486
     * const nodeElement: HTMLElement = node.nativeElement;
487
     * ```
488
     */
489
    /** @hidden @internal */
490
    public get nativeElement() {
491
        return this.element.nativeElement;
1,951✔
492
    }
493

494
    /** @hidden @internal */
495
    public ngOnInit() {
496
        this.openAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(
3,529✔
497
            () => {
498
                this.tree.nodeExpanded.emit({ owner: this.tree, node: this });
12✔
499
            }
500
        );
501
        this.closeAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => {
3,529✔
502
            this.tree.nodeCollapsed.emit({ owner: this.tree, node: this });
3✔
503
            this.treeService.collapse(this);
3✔
504
            this.cdr.markForCheck();
3✔
505
        });
506
    }
507

508
    /**
509
     * @hidden @internal
510
     * Sets the focus to the node's <a> child, if present
511
     * Sets the node as the tree service's focusedNode
512
     * Marks the node as the current active element
513
     */
514
    public handleFocus(): void {
515
        if (this.disabled) {
48!
516
            return;
×
517
        }
518
        if (this.navService.focusedNode !== this) {
48!
519
            this.navService.focusedNode = this;
×
520
        }
521
        this.isFocused = true;
48✔
522
        if (this.linkChildren?.length) {
48✔
523
            this.linkChildren.first.nativeElement.focus();
1✔
524
            return;
1✔
525
        }
526
        if (this.registeredChildren.length) {
47✔
527
            this.registeredChildren[0].elementRef.nativeElement.focus();
1✔
528
            return;
1✔
529
        }
530
    }
531

532
    /**
533
     * @hidden @internal
534
     * Clear the node's focused status
535
     */
536
    public clearFocus(): void {
537
        this.isFocused = false;
32✔
538
    }
539

540
    /**
541
     * @hidden @internal
542
     */
543
    public onSelectorPointerDown(event) {
544
        event.preventDefault();
×
545
        event.stopPropagation()
×
546
    }
547

548
    /**
549
     * @hidden @internal
550
     */
551
    public onSelectorClick(event) {
552
        // event.stopPropagation();
553
        event.preventDefault();
30✔
554
        // this.navService.handleFocusedAndActiveNode(this);
555
        if (event.shiftKey) {
30✔
556
            this.selectionService.selectMultipleNodes(this, event);
2✔
557
            return;
2✔
558
        }
559
        if (this.selected) {
28✔
560
            this.selectionService.deselectNode(this, event);
11✔
561
        } else {
562
            this.selectionService.selectNode(this, event);
17✔
563
        }
564
    }
565

566
    /**
567
     * Toggles the node expansion state, triggering animation
568
     *
569
     * ```html
570
     * <igx-tree>
571
     *      <igx-tree-node #node>My Node</igx-tree-node>
572
     * </igx-tree>
573
     * <button type="button" igxButton (click)="node.toggle()">Toggle Node</button>
574
     * ```
575
     *
576
     * ```typescript
577
     * const myNode: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
578
     * myNode.toggle();
579
     * ```
580
     */
581
    public toggle() {
582
        if (this.expanded) {
13✔
583
            this.collapse();
1✔
584
        } else {
585
            this.expand();
12✔
586
        }
587
    }
588

589
    /** @hidden @internal */
590
    public indicatorClick() {
591
        if(!this.tree.toggleNodeOnClick) {
10✔
592
            this.toggle();
10✔
593
            this.navService.setFocusedAndActiveNode(this);
10✔
594
        }
595
    }
596

597
    /**
598
     * @hidden @internal
599
     */
600
    public onPointerDown(event) {
601
        event.stopPropagation();
25✔
602

603
        //Toggle the node only on left mouse click - https://w3c.github.io/pointerevents/#button-states
604
        if(this.tree.toggleNodeOnClick && event.button === 0) {
25✔
605
            this.toggle();
1✔
606
        }
607

608
        this.navService.setFocusedAndActiveNode(this);
25✔
609
    }
610

611
    public override ngOnDestroy() {
612
        super.ngOnDestroy();
3,541✔
613
        this.selectionService.ensureStateOnNodeDelete(this);
3,541✔
614
    }
615

616
    /**
617
     * Expands the node, triggering animation
618
     *
619
     * ```html
620
     * <igx-tree>
621
     *      <igx-tree-node #node>My Node</igx-tree-node>
622
     * </igx-tree>
623
     * <button type="button" igxButton (click)="node.expand()">Expand Node</button>
624
     * ```
625
     *
626
     * ```typescript
627
     * const myNode: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
628
     * myNode.expand();
629
     * ```
630
     */
631
    public expand() {
632
        if (this.expanded && !this.treeService.collapsingNodes.has(this)) {
27✔
633
            return;
1✔
634
        }
635
        const args: ITreeNodeTogglingEventArgs = {
26✔
636
            owner: this.tree,
637
            node: this,
638
            cancel: false
639

640
        };
641
        this.tree.nodeExpanding.emit(args);
26✔
642
        if (!args.cancel) {
26✔
643
            this.treeService.expand(this, true);
25✔
644
            this.cdr.detectChanges();
25✔
645
            this.playOpenAnimation(
25✔
646
                this.childrenContainer
647
            );
648
        }
649
    }
650

651
    /**
652
     * Collapses the node, triggering animation
653
     *
654
     * ```html
655
     * <igx-tree>
656
     *      <igx-tree-node #node>My Node</igx-tree-node>
657
     * </igx-tree>
658
     * <button type="button" igxButton (click)="node.collapse()">Collapse Node</button>
659
     * ```
660
     *
661
     * ```typescript
662
     * const myNode: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
663
     * myNode.collapse();
664
     * ```
665
     */
666
    public collapse() {
667
        if (!this.expanded || this.treeService.collapsingNodes.has(this)) {
6✔
668
            return;
2✔
669
        }
670
        const args: ITreeNodeTogglingEventArgs = {
4✔
671
            owner: this.tree,
672
            node: this,
673
            cancel: false
674

675
        };
676
        this.tree.nodeCollapsing.emit(args);
4✔
677
        if (!args.cancel) {
4✔
678
            this.treeService.collapsing(this);
3✔
679
            this.playCloseAnimation(
3✔
680
                this.childrenContainer
681
            );
682
        }
683
    }
684

685
    /** @hidden @internal */
686
    public addLinkChild(link: IgxTreeNodeLinkDirective) {
687
        this._tabIndex = -1;
15✔
688
        this.registeredChildren.push(link);
15✔
689
    }
690

691
    /** @hidden @internal */
692
    public removeLinkChild(link: IgxTreeNodeLinkDirective) {
693
        const index = this.registeredChildren.indexOf(link);
30✔
694
        if (index !== -1) {
30✔
695
            this.registeredChildren.splice(index, 1);
15✔
696
        }
697
    }
698
}
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