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

IgniteUI / igniteui-angular / 20191011486

13 Dec 2025 10:50AM UTC coverage: 91.504% (+0.003%) from 91.501%
20191011486

push

github

web-flow
refactor(*): New localization implementation. (#16034)

14236 of 16778 branches covered (84.85%)

378 of 419 new or added lines in 61 files covered. (90.21%)

1 existing line in 1 file now uncovered.

28649 of 31309 relevant lines covered (91.5%)

34896.51 hits per line

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

93.48
/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 } 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
    imports: [NgTemplateOutlet, IgxIconComponent, IgxCheckboxComponent, NgClass, IgxCircularProgressBarComponent]
132
})
133
export class IgxTreeNodeComponent<T> extends ToggleAnimationPlayer implements IgxTreeNode<T>, OnInit, OnDestroy {
3✔
134
    public tree = inject<IgxTree>(IGX_TREE_COMPONENT);
3,522✔
135
    protected selectionService = inject(IgxTreeSelectionService);
3,522✔
136
    protected treeService = inject(IgxTreeService);
3,522✔
137
    protected navService = inject(IgxTreeNavigationService);
3,522✔
138
    protected cdr = inject(ChangeDetectorRef);
3,522✔
139
    private element = inject<ElementRef<HTMLElement>>(ElementRef);
3,522✔
140
    public parentNode = inject<IgxTreeNode<any>>(IGX_TREE_NODE_COMPONENT, { optional: true, skipSelf: true });
3,522✔
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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