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

IgniteUI / igniteui-angular / 29572405564

17 Jul 2026 10:07AM UTC coverage: 90.116% (-0.02%) from 90.135%
29572405564

Pull #15125

github

web-flow
Merge 637b7229e into 8ebabbb38
Pull Request #15125: refactor(*): bundle styles with components

14920 of 17397 branches covered (85.76%)

Branch coverage included in aggregate %.

30030 of 32483 relevant lines covered (92.45%)

34495.14 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 {
2
    ChangeDetectorRef,
3
    Component,
4
    ContentChildren,
5
    Directive,
6
    ElementRef,
7
    EventEmitter,
8
    HostBinding,
9
    HostListener,
10
    Input,
11
    OnDestroy,
12
    OnInit,
13
    Output,
14
    QueryList,
15
    TemplateRef,
16
    ViewChild,
17
    booleanAttribute,
18
    inject,
19
    ChangeDetectionStrategy,
20
    ViewEncapsulation,
21
} from '@angular/core';
22
import { takeUntil } from 'rxjs/operators';
23
import {
24
    IgxTree,
25
    IgxTreeNode,
26
    IgxTreeSelectionType,
27
    IGX_TREE_COMPONENT,
28
    IGX_TREE_NODE_COMPONENT,
29
    ITreeNodeTogglingEventArgs
30
} from '../common';
31
import { IgxTreeNavigationService } from '../tree-navigation.service';
32
import { IgxTreeSelectionService } from '../tree-selection.service';
33
import { IgxTreeService } from '../tree.service';
34
import { NgTemplateOutlet, NgClass } from '@angular/common';
35
import { IgxIconComponent } from 'igniteui-angular/icon';
36
import { IgxCheckboxComponent } from 'igniteui-angular/checkbox';
37
import { IgxCircularProgressBarComponent } from 'igniteui-angular/progressbar';
38
import { ToggleAnimationPlayer, ToggleAnimationSettings } from 'igniteui-angular/expansion-panel';
39
import { getCurrentResourceStrings, onResourceChangeHandle, ITreeResourceStrings, TreeResourceStringsEN } from 'igniteui-angular/core';
40

41
// TODO: Implement aria functionality
42
/**
43
 * @hidden @internal
44
 * Used for links (`a` tags) in the body of an `igx-tree-node`. Handles aria and event dispatch.
45
 */
46
@Directive({
47
    selector: `[igxTreeNodeLink]`,
48
    standalone: true
49
})
50
export class IgxTreeNodeLinkDirective implements OnDestroy {
3✔
51
    private node = inject<IgxTreeNode<any>>(IGX_TREE_NODE_COMPONENT, { optional: true });
30✔
52
    private navService = inject(IgxTreeNavigationService);
30✔
53
    public elementRef = inject(ElementRef);
30✔
54

55

56
    @HostBinding('attr.role')
57
    public role = 'treeitem';
30✔
58

59
    /**
60
     * The node's parent. Should be used only when the link is defined
61
     * in `<ng-template>` tag outside of its parent, as Angular DI will not properly provide a reference
62
     *
63
     * ```html
64
     * <igx-tree>
65
     *     <igx-tree-node #myNode *ngFor="let node of data" [data]="node">
66
     *         <ng-template *ngTemplateOutlet="nodeTemplate; context: { $implicit: data, parentNode: myNode }">
67
     *         </ng-template>
68
     *     </igx-tree-node>
69
     *     ...
70
     *     <!-- node template is defined under tree to access related services -->
71
     *     <ng-template #nodeTemplate let-data let-node="parentNode">
72
     *         <a [igxTreeNodeLink]="node">{{ data.label }}</a>
73
     *     </ng-template>
74
     * </igx-tree>
75
     * ```
76
     */
77
    @Input('igxTreeNodeLink')
78
    public set parentNode(val: any) {
79
        if (val) {
30✔
80
            this._parentNode = val;
15✔
81
            (this._parentNode as any).addLinkChild(this);
15✔
82
        }
83
    }
84

85
    public get parentNode(): any {
86
        return this._parentNode;
113✔
87
    }
88

89
    /** A pointer to the parent node */
90
    private get target(): IgxTreeNode<any> {
91
        return this.node || this.parentNode;
226✔
92
    }
93

94
    private _parentNode: IgxTreeNode<any> = null;
30✔
95

96
    /** @hidden @internal */
97
    @HostBinding('attr.tabindex')
98
    public get tabIndex(): number {
99
        return this.navService.focusedNode === this.target ? (this.target?.disabled ? -1 : 0) : -1;
181!
100
    }
101

102
    /**
103
     * @hidden @internal
104
     * Clear the node's focused state
105
     */
106
    @HostListener('blur')
107
    public handleBlur() {
108
        this.target.isFocused = false;
×
109
    }
110

111
    /**
112
     * @hidden @internal
113
     * Set the node as focused
114
     */
115
    @HostListener('focus')
116
    public handleFocus() {
117
        if (this.target && !this.target.disabled) {
2✔
118
            if (this.navService.focusedNode !== this.target) {
2!
119
                this.navService.focusedNode = this.target;
×
120
            }
121
            this.target.isFocused = true;
2✔
122
        }
123
    }
124

125
    public ngOnDestroy() {
126
        this.target.removeLinkChild(this);
30✔
127
    }
128
}
129

130
/**
131
 *
132
 * The tree node component represents a child node of the tree component or another tree node.
133
 * Usage:
134
 *
135
 * ```html
136
 *  <igx-tree>
137
 *  ...
138
 *    <igx-tree-node [data]="data" [selected]="service.isNodeSelected(data.Key)" [expanded]="service.isNodeExpanded(data.Key)">
139
 *      {{ data.FirstName }} {{ data.LastName }}
140
 *    </igx-tree-node>
141
 *  ...
142
 *  </igx-tree>
143
 * ```
144
 */
145
@Component({
146
    selector: 'igx-tree-node',
147
    templateUrl: 'tree-node.component.html',
148
    styleUrl: 'tree-node.component.css',
149
    encapsulation: ViewEncapsulation.None,
150
    providers: [
151
        { provide: IGX_TREE_NODE_COMPONENT, useExisting: IgxTreeNodeComponent }
152
    ],
153
    changeDetection: ChangeDetectionStrategy.Eager,
154
    imports: [NgTemplateOutlet, IgxIconComponent, IgxCheckboxComponent, NgClass, IgxCircularProgressBarComponent]
155
})
156
export class IgxTreeNodeComponent<T> extends ToggleAnimationPlayer implements IgxTreeNode<T>, OnInit, OnDestroy {
3✔
157
    public tree = inject<IgxTree>(IGX_TREE_COMPONENT);
3,540✔
158
    protected selectionService = inject(IgxTreeSelectionService);
3,540✔
159
    protected treeService = inject(IgxTreeService);
3,540✔
160
    protected navService = inject(IgxTreeNavigationService);
3,540✔
161
    protected cdr = inject(ChangeDetectorRef);
3,540✔
162
    private element = inject<ElementRef<HTMLElement>>(ElementRef);
3,540✔
163
    public parentNode = inject<IgxTreeNode<any>>(IGX_TREE_NODE_COMPONENT, { optional: true, skipSelf: true });
3,540✔
164

165
    /**
166
     * The data entry that the node is visualizing.
167
     *
168
     * @remarks
169
     * Required for searching through nodes.
170
     *
171
     * @example
172
     * ```html
173
     *  <igx-tree>
174
     *  ...
175
     *    <igx-tree-node [data]="data">
176
     *      {{ data.FirstName }} {{ data.LastName }}
177
     *    </igx-tree-node>
178
     *  ...
179
     *  </igx-tree>
180
     * ```
181
     */
182
    @Input()
183
    public data: T;
184

185
    /**
186
     * To be used for load-on-demand scenarios in order to specify whether the node is loading data.
187
     *
188
     * @remarks
189
     * Loading nodes do not render children.
190
     */
191
    @Input({ transform: booleanAttribute })
192
    public loading = false;
3,540✔
193

194
    // TO DO: return different tab index depending on anchor child
195
    /** @hidden @internal */
196
    public set tabIndex(val: number) {
197
        this._tabIndex = val;
73✔
198
    }
199

200
    /** @hidden @internal */
201
    public get tabIndex(): number {
202
        if (this.disabled) {
38,249✔
203
            return -1;
736✔
204
        }
205
        if (this._tabIndex === null) {
37,513✔
206
            if (this.navService.focusedNode === null) {
37,157✔
207
                return this.hasLinkChildren ? -1 : 0;
32,630✔
208
            }
209
            return -1;
4,527✔
210
        }
211
        return this.hasLinkChildren ? -1 : this._tabIndex;
356✔
212
    }
213

214
    /** @hidden @internal */
215
    public override get animationSettings(): ToggleAnimationSettings {
216
        return this.tree.animationSettings;
25✔
217
    }
218

219
    /**
220
     * Gets/Sets the resource strings.
221
     *
222
     * @remarks
223
     * Uses EN resources by default.
224
     */
225
    @Input()
226
    public set resourceStrings(value: ITreeResourceStrings) {
227
        this._resourceStrings = Object.assign({}, this._resourceStrings, value);
×
228
    }
229

230
    /**
231
     * An accessor that returns the resource strings.
232
     */
233
    public get resourceStrings(): ITreeResourceStrings {
234
        return this._resourceStrings || this._defaultResourceStrings;
21,887✔
235
    }
236

237
    /**
238
     * Gets/Sets the active state of the node
239
     *
240
     * @param value: boolean
241
     */
242
    @Input({ transform: booleanAttribute })
243
    public set active(value: boolean) {
244
        if (value) {
247✔
245
            this.navService.activeNode = this;
175✔
246
            this.tree.activeNodeBindingChange.emit(this);
175✔
247
        }
248
    }
249

250
    public get active(): boolean {
251
        return this.navService.activeNode === this;
38,250✔
252
    }
253

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

272
    /**
273
     * Emitted when the node's `expanded` property changes.
274
     *
275
     * ```html
276
     * <igx-tree>
277
     *      <igx-tree-node *ngFor="let node of data" [data]="node" [(expanded)]="node.expanded">
278
     *      </igx-tree-node>
279
     * </igx-tree>
280
     * ```
281
     *
282
     * ```typescript
283
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
284
     * node.expandedChange.pipe(takeUntil(this.destroy$)).subscribe((e: boolean) => console.log("Node expansion state changed to ", e))
285
     * ```
286
     */
287
    @Output()
288
    public expandedChange = new EventEmitter<boolean>();
3,540✔
289

290
    /** @hidden @internal */
291
    public get focused() {
292
        return this.isFocused &&
38,249✔
293
            this.navService.focusedNode === this;
294
    }
295

296
    /**
297
     * Retrieves the full path to the node incuding itself
298
     *
299
     * ```typescript
300
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
301
     * const path: IgxTreeNode<any>[] = node.path;
302
     * ```
303
     */
304
    public get path(): IgxTreeNode<any>[] {
305
        return this.parentNode?.path ? [...this.parentNode.path, this] : [this];
665✔
306
    }
307

308
    // TODO: bind to disabled state when node is dragged
309
    /**
310
     * Gets/Sets the disabled state of the node
311
     *
312
     * @param value: boolean
313
     */
314
    @Input({ transform: booleanAttribute })
315
    @HostBinding('class.igx-tree-node--disabled')
316
    public get disabled(): boolean {
317
        return this._disabled;
122,368✔
318
    }
319

320
    public set disabled(value: boolean) {
321
        if (value !== this._disabled) {
398✔
322
            this._disabled = value;
83✔
323
            this.tree.disabledChange.emit(this);
83✔
324
        }
325
    }
326

327
    /** @hidden @internal */
328
    @HostBinding('class.igx-tree-node')
329
    public cssClass = 'igx-tree-node';
3,540✔
330

331
    /** @hidden @internal */
332
    @HostBinding('attr.role')
333
    public get role() {
334
        return this.hasLinkChildren ? 'none' : 'treeitem';
76,475✔
335
    }
336

337
    /** @hidden @internal */
338
    @ContentChildren(IgxTreeNodeLinkDirective, { read: ElementRef })
339
    public linkChildren: QueryList<ElementRef>;
340

341
    /** @hidden @internal */
342
    @ContentChildren(IGX_TREE_NODE_COMPONENT, { read: IGX_TREE_NODE_COMPONENT })
343
    public _children: QueryList<IgxTreeNode<any>>;
344

345
    /** @hidden @internal */
346
    @ContentChildren(IGX_TREE_NODE_COMPONENT, { read: IGX_TREE_NODE_COMPONENT, descendants: true })
347
    public allChildren: QueryList<IgxTreeNode<any>>;
348

349
    /**
350
     * Return the child nodes of the node (if any)
351
     *
352
     * @remarks
353
     * Returns `null` if node does not have children
354
     *
355
     * @example
356
     * ```typescript
357
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
358
     * const children: IgxTreeNode<any>[] = node.children;
359
     * ```
360
     */
361
    public get children(): IgxTreeNode<any>[] {
362
        return this._children?.length ? this._children.toArray() : null;
×
363
    }
364

365
    // TODO: will be used in Drag and Drop implementation
366
    /** @hidden @internal */
367
    @ViewChild('ghostTemplate', { read: ElementRef })
368
    public header: ElementRef;
369

370
    @ViewChild('defaultIndicator', { read: TemplateRef, static: true })
371
    private _defaultExpandIndicatorTemplate: TemplateRef<any>;
372

373
    @ViewChild('childrenContainer', { read: ElementRef })
374
    private childrenContainer: ElementRef;
375

376
    private get hasLinkChildren(): boolean {
377
        return this.linkChildren?.length > 0 || this.registeredChildren?.length > 0;
109,461✔
378
    }
379

380
    /** @hidden @internal */
381
    public isFocused: boolean;
382

383
    /** @hidden @internal */
384
    public registeredChildren: IgxTreeNodeLinkDirective[] = [];
3,540✔
385

386
    private _resourceStrings: ITreeResourceStrings = null;
3,540✔
387
    private _defaultResourceStrings = getCurrentResourceStrings(TreeResourceStringsEN);
3,540✔
388
    private _tabIndex = null;
3,540✔
389
    private _disabled = false;
3,540✔
390

391
    constructor() {
392
        super();
3,540✔
393
        onResourceChangeHandle(this.destroy$, () => {
3,540✔
394
            this._defaultResourceStrings = getCurrentResourceStrings(TreeResourceStringsEN, false);
×
395
        }, this);
396
    }
397

398
    /**
399
     * @hidden @internal
400
     */
401
    public get showSelectors() {
402
        return this.tree.selection !== IgxTreeSelectionType.None;
38,249✔
403
    }
404

405
    /**
406
     * @hidden @internal
407
     */
408
    public get indeterminate(): boolean {
409
        return this.selectionService.isNodeIndeterminate(this);
7,613✔
410
    }
411

412
    /** The depth of the node, relative to the root
413
     *
414
     * ```html
415
     * <igx-tree>
416
     *  ...
417
     *  <igx-tree-node #node>
418
     *      My level is {{ node.level }}
419
     *  </igx-tree-node>
420
     * </igx-tree>
421
     * ```
422
     *
423
     * ```typescript
424
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[12])[0];
425
     * const level: number = node.level;
426
     * ```
427
     */
428
    public get level(): number {
429
        return this.parentNode ? this.parentNode.level + 1 : 0;
195,120✔
430
    }
431

432
    /** Get/set whether the node is selected. Supporst two-way binding.
433
     *
434
     * ```html
435
     * <igx-tree>
436
     *  ...
437
     *  <igx-tree-node *ngFor="let node of data" [(selected)]="node.selected">
438
     *      {{ node.label }}
439
     *  </igx-tree-node>
440
     * </igx-tree>
441
     * ```
442
     *
443
     * ```typescript
444
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
445
     * const selected = node.selected;
446
     * node.selected = true;
447
     * ```
448
     */
449
    @Input({ transform: booleanAttribute })
450
    public get selected(): boolean {
451
        return this.selectionService.isNodeSelected(this);
46,582✔
452
    }
453

454
    public set selected(val: boolean) {
455
        if (!(this.tree?.nodes && this.tree.nodes.find((e) => e === this)) && val) {
5,496✔
456
            this.tree.forceSelect.push(this);
357✔
457
            return;
357✔
458
        }
459
        if (val && !this.selectionService.isNodeSelected(this)) {
880✔
460
            this.selectionService.selectNodesWithNoEvent([this]);
98✔
461
        }
462
        if (!val && this.selectionService.isNodeSelected(this)) {
880✔
463
            this.selectionService.deselectNodesWithNoEvent([this]);
9✔
464
        }
465
    }
466

467
    /** Get/set whether the node is expanded
468
     *
469
     * ```html
470
     * <igx-tree>
471
     *  ...
472
     *  <igx-tree-node *ngFor="let node of data" [expanded]="node.name === this.expandedNode">
473
     *      {{ node.label }}
474
     *  </igx-tree-node>
475
     * </igx-tree>
476
     * ```
477
     *
478
     * ```typescript
479
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
480
     * const expanded = node.expanded;
481
     * node.expanded = true;
482
     * ```
483
     */
484
    @Input({ transform: booleanAttribute })
485
    public get expanded() {
486
        return this.treeService.isExpanded(this);
121,256✔
487
    }
488

489
    public set expanded(val: boolean) {
490
        if (val) {
1,668✔
491
            this.treeService.expand(this, false);
76✔
492
        } else {
493
            this.treeService.collapse(this);
1,592✔
494
        }
495
    }
496

497
    /** @hidden @internal */
498
    public get expandIndicatorTemplate(): TemplateRef<any> {
499
        return this.tree?.expandIndicator || this._defaultExpandIndicatorTemplate;
38,249✔
500
    }
501

502
    /**
503
     * The native DOM element representing the node. Could be null in certain environments.
504
     *
505
     * ```typescript
506
     * // get the nativeElement of the second node
507
     * const node: IgxTreeNode = this.tree.nodes.first();
508
     * const nodeElement: HTMLElement = node.nativeElement;
509
     * ```
510
     */
511
    /** @hidden @internal */
512
    public get nativeElement() {
513
        return this.element.nativeElement;
1,951✔
514
    }
515

516
    /** @hidden @internal */
517
    public ngOnInit() {
518
        this.openAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(
3,529✔
519
            () => {
520
                this.tree.nodeExpanded.emit({ owner: this.tree, node: this });
12✔
521
            }
522
        );
523
        this.closeAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => {
3,529✔
524
            this.tree.nodeCollapsed.emit({ owner: this.tree, node: this });
3✔
525
            this.treeService.collapse(this);
3✔
526
            this.cdr.markForCheck();
3✔
527
        });
528
    }
529

530
    /**
531
     * @hidden @internal
532
     * Sets the focus to the node's <a> child, if present
533
     * Sets the node as the tree service's focusedNode
534
     * Marks the node as the current active element
535
     */
536
    public handleFocus(): void {
537
        if (this.disabled) {
48!
538
            return;
×
539
        }
540
        if (this.navService.focusedNode !== this) {
48!
541
            this.navService.focusedNode = this;
×
542
        }
543
        this.isFocused = true;
48✔
544
        if (this.linkChildren?.length) {
48✔
545
            this.linkChildren.first.nativeElement.focus();
1✔
546
            return;
1✔
547
        }
548
        if (this.registeredChildren.length) {
47✔
549
            this.registeredChildren[0].elementRef.nativeElement.focus();
1✔
550
            return;
1✔
551
        }
552
    }
553

554
    /**
555
     * @hidden @internal
556
     * Clear the node's focused status
557
     */
558
    public clearFocus(): void {
559
        this.isFocused = false;
32✔
560
    }
561

562
    /**
563
     * @hidden @internal
564
     */
565
    public onSelectorPointerDown(event) {
566
        event.preventDefault();
×
567
        event.stopPropagation()
×
568
    }
569

570
    /**
571
     * @hidden @internal
572
     */
573
    public onSelectorClick(event) {
574
        // event.stopPropagation();
575
        event.preventDefault();
30✔
576
        // this.navService.handleFocusedAndActiveNode(this);
577
        if (event.shiftKey) {
30✔
578
            this.selectionService.selectMultipleNodes(this, event);
2✔
579
            return;
2✔
580
        }
581
        if (this.selected) {
28✔
582
            this.selectionService.deselectNode(this, event);
11✔
583
        } else {
584
            this.selectionService.selectNode(this, event);
17✔
585
        }
586
    }
587

588
    /**
589
     * Toggles the node expansion state, triggering animation
590
     *
591
     * ```html
592
     * <igx-tree>
593
     *      <igx-tree-node #node>My Node</igx-tree-node>
594
     * </igx-tree>
595
     * <button type="button" igxButton (click)="node.toggle()">Toggle Node</button>
596
     * ```
597
     *
598
     * ```typescript
599
     * const myNode: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
600
     * myNode.toggle();
601
     * ```
602
     */
603
    public toggle() {
604
        if (this.expanded) {
13✔
605
            this.collapse();
1✔
606
        } else {
607
            this.expand();
12✔
608
        }
609
    }
610

611
    /** @hidden @internal */
612
    public indicatorClick() {
613
        if(!this.tree.toggleNodeOnClick) {
10✔
614
            this.toggle();
10✔
615
            this.navService.setFocusedAndActiveNode(this);
10✔
616
        }
617
    }
618

619
    /**
620
     * @hidden @internal
621
     */
622
    public onPointerDown(event) {
623
        event.stopPropagation();
25✔
624

625
        //Toggle the node only on left mouse click - https://w3c.github.io/pointerevents/#button-states
626
        if(this.tree.toggleNodeOnClick && event.button === 0) {
25✔
627
            this.toggle();
1✔
628
        }
629

630
        this.navService.setFocusedAndActiveNode(this);
25✔
631
    }
632

633
    public override ngOnDestroy() {
634
        super.ngOnDestroy();
3,541✔
635
        this.selectionService.ensureStateOnNodeDelete(this);
3,541✔
636
    }
637

638
    /**
639
     * Expands the node, triggering animation
640
     *
641
     * ```html
642
     * <igx-tree>
643
     *      <igx-tree-node #node>My Node</igx-tree-node>
644
     * </igx-tree>
645
     * <button type="button" igxButton (click)="node.expand()">Expand Node</button>
646
     * ```
647
     *
648
     * ```typescript
649
     * const myNode: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
650
     * myNode.expand();
651
     * ```
652
     */
653
    public expand() {
654
        if (this.expanded && !this.treeService.collapsingNodes.has(this)) {
27✔
655
            return;
1✔
656
        }
657
        const args: ITreeNodeTogglingEventArgs = {
26✔
658
            owner: this.tree,
659
            node: this,
660
            cancel: false
661

662
        };
663
        this.tree.nodeExpanding.emit(args);
26✔
664
        if (!args.cancel) {
26✔
665
            this.treeService.expand(this, true);
25✔
666
            this.cdr.detectChanges();
25✔
667
            this.playOpenAnimation(
25✔
668
                this.childrenContainer
669
            );
670
        }
671
    }
672

673
    /**
674
     * Collapses the node, triggering animation
675
     *
676
     * ```html
677
     * <igx-tree>
678
     *      <igx-tree-node #node>My Node</igx-tree-node>
679
     * </igx-tree>
680
     * <button type="button" igxButton (click)="node.collapse()">Collapse Node</button>
681
     * ```
682
     *
683
     * ```typescript
684
     * const myNode: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
685
     * myNode.collapse();
686
     * ```
687
     */
688
    public collapse() {
689
        if (!this.expanded || this.treeService.collapsingNodes.has(this)) {
6✔
690
            return;
2✔
691
        }
692
        const args: ITreeNodeTogglingEventArgs = {
4✔
693
            owner: this.tree,
694
            node: this,
695
            cancel: false
696

697
        };
698
        this.tree.nodeCollapsing.emit(args);
4✔
699
        if (!args.cancel) {
4✔
700
            this.treeService.collapsing(this);
3✔
701
            this.playCloseAnimation(
3✔
702
                this.childrenContainer
703
            );
704
        }
705
    }
706

707
    /** @hidden @internal */
708
    public addLinkChild(link: IgxTreeNodeLinkDirective) {
709
        this._tabIndex = -1;
15✔
710
        this.registeredChildren.push(link);
15✔
711
    }
712

713
    /** @hidden @internal */
714
    public removeLinkChild(link: IgxTreeNodeLinkDirective) {
715
        const index = this.registeredChildren.indexOf(link);
30✔
716
        if (index !== -1) {
30✔
717
            this.registeredChildren.splice(index, 1);
15✔
718
        }
719
    }
720
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc