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

IgniteUI / igniteui-angular / 6653488239

26 Oct 2023 11:33AM UTC coverage: 92.101% (-0.1%) from 92.206%
6653488239

push

github

web-flow
Merge pull request #13451 from IgniteUI/bundle-test-extended

refactor(i18n, util): tree shaking i18n

15273 of 17962 branches covered (0.0%)

45 of 45 new or added lines in 24 files covered. (100.0%)

26410 of 28675 relevant lines covered (92.1%)

30213.01 hits per line

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

94.37
/projects/igniteui-angular/src/lib/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
    Inject,
11
    Input,
12
    OnDestroy,
13
    OnInit,
14
    Optional,
15
    Output,
16
    QueryList,
17
    SkipSelf,
18
    TemplateRef,
19
    ViewChild
20
} from '@angular/core';
21
import { takeUntil } from 'rxjs/operators';
22
import { DisplayDensity } from '../../core/density';
23
import { ITreeResourceStrings, TreeResourceStringsEN } from '../../core/i18n/tree-resources';
24
import { ToggleAnimationPlayer, ToggleAnimationSettings } from '../../expansion-panel/toggle-animation-component';
2✔
25
import { IgxAngularAnimationService } from '../../services/animation/angular-animation-service';
26
import { AnimationService } from '../../services/animation/animation';
30✔
27
import {
15✔
28
    IgxTree,
15✔
29
    IgxTreeNode,
30
    IgxTreeSelectionType,
31
    IGX_TREE_COMPONENT,
32
    IGX_TREE_NODE_COMPONENT,
113✔
33
    ITreeNodeTogglingEventArgs
34
} from '../common';
35
import { IgxTreeNavigationService } from '../tree-navigation.service';
36
import { IgxTreeSelectionService } from '../tree-selection.service';
226✔
37
import { IgxTreeService } from '../tree.service';
38
import { IgxCircularProgressBarComponent } from '../../progressbar/progressbar.component';
39
import { IgxCheckboxComponent } from '../../checkbox/checkbox.component';
30✔
40
import { IgxIconComponent } from '../../icon/icon.component';
30✔
41
import { NgTemplateOutlet, NgIf, NgClass, NgFor } from '@angular/common';
30✔
42
import { getCurrentResourceStrings } from '../../core/i18n/resources';
30✔
43

30✔
44
// TODO: Implement aria functionality
45
/**
46
 * @hidden @internal
181!
47
 * Used for links (`a` tags) in the body of an `igx-tree-node`. Handles aria and event dispatch.
48
 */
49
@Directive({
×
50
    selector: `[igxTreeNodeLink]`,
51
    standalone: true
52
})
2!
53
export class IgxTreeNodeLinkDirective implements OnDestroy {
2!
54

×
55
    @HostBinding('attr.role')
56
    public role = 'treeitem';
2✔
57

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

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

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

93
    private _parentNode: IgxTreeNode<any> = null;
94

95
    constructor(@Optional() @Inject(IGX_TREE_NODE_COMPONENT)
96
    private node: IgxTreeNode<any>,
97
        private navService: IgxTreeNavigationService,
2✔
98
        public elementRef: ElementRef) {
99
    }
100

101
    /** @hidden @internal */
70✔
102
    @HostBinding('attr.tabindex')
103
    public get tabIndex(): number {
104
        return this.navService.focusedNode === this.target ? (this.target?.disabled ? -1 : 0) : -1;
105
    }
37,545✔
106

736✔
107
    /**
108
     * @hidden @internal
36,809✔
109
     * Clear the node's focused state
36,487✔
110
     */
32,132✔
111
    @HostListener('blur')
112
    public handleBlur() {
4,355✔
113
        this.target.isFocused = false;
114
    }
322✔
115

116
    /**
117
     * @hidden @internal
118
     * Set the node as focused
23✔
119
     */
120
    @HostListener('focus')
121
    public handleFocus() {
×
122
        if (this.target && !this.target.disabled) {
123
            if (this.navService.focusedNode !== this.target) {
124
                this.navService.focusedNode = this.target;
125
            }
126
            this.target.isFocused = true;
127
        }
21,183✔
128
    }
129

130
    public ngOnDestroy() {
231✔
131
        this.target.removeLinkChild(this);
171✔
132
    }
171✔
133
}
134

135
/**
136
 *
37,546✔
137
 * The tree node component represents a child node of the tree component or another tree node.
138
 * Usage:
139
 *
140
 * ```html
37,545✔
141
 *  <igx-tree>
142
 *  ...
143
 *    <igx-tree-node [data]="data" [selected]="service.isNodeSelected(data.Key)" [expanded]="service.isNodeExpanded(data.Key)">
144
 *      {{ data.FirstName }} {{ data.LastName }}
145
 *    </igx-tree-node>
146
 *  ...
147
 *  </igx-tree>
148
 * ```
149
 */
150
@Component({
151
    selector: 'igx-tree-node',
152
    templateUrl: 'tree-node.component.html',
690✔
153
    providers: [
154
        { provide: IGX_TREE_NODE_COMPONENT, useExisting: IgxTreeNodeComponent }
155
    ],
112,774✔
156
    standalone: true,
157
    imports: [NgTemplateOutlet, NgIf, IgxIconComponent, IgxCheckboxComponent, NgClass, NgFor, IgxCircularProgressBarComponent]
158
})
342✔
159
export class IgxTreeNodeComponent<T> extends ToggleAnimationPlayer implements IgxTreeNode<T>, OnInit, OnDestroy {
83✔
160
    /**
83✔
161
     * The data entry that the node is visualizing.
162
     *
163
     * @remarks
164
     * Required for searching through nodes.
37,524!
165
     *
166
     * @example
×
167
     * ```html
168
     *  <igx-tree>
×
169
     *  ...
170
     *    <igx-tree-node [data]="data">
171
     *      {{ data.FirstName }} {{ data.LastName }}
37,524✔
172
     *    </igx-tree-node>
173
     *  ...
174
     *  </igx-tree>
175
     * ```
75,069✔
176
     */
177
    @Input()
178
    public data: T;
179

180
    /**
181
     * To be used for load-on-demand scenarios in order to specify whether the node is loading data.
182
     *
183
     * @remarks
184
     * Loading nodes do not render children.
185
     */
186
    @Input()
187
    public loading = false;
188

189
    // TO DO: return different tab index depending on anchor child
190
    /** @hidden @internal */
×
191
    public set tabIndex(val: number) {
192
        this._tabIndex = val;
193
    }
107,523✔
194

195
    /** @hidden @internal */
196
    public get tabIndex(): number {
197
        if (this.disabled) {
3✔
198
            return -1;
199
        }
200
        if (this._tabIndex === null) {
201
            if (this.navService.focusedNode === null) {
3✔
202
                return this.hasLinkChildren ? -1 : 0;
203
            }
204
            return -1;
3,368✔
205
        }
3,368✔
206
        return this.hasLinkChildren ? -1 : this._tabIndex;
3,368✔
207
    }
3,368✔
208

3,368✔
209
    /** @hidden @internal */
3,368✔
210
    public override get animationSettings(): ToggleAnimationSettings {
3,368✔
211
        return this.tree.animationSettings;
3,368✔
212
    }
3,368✔
213

3,368✔
214
    /**
3,368✔
215
     * Gets/Sets the resource strings.
3,368✔
216
     *
217
     * @remarks
3,368✔
218
     * Uses EN resources by default.
219
     */
3,368✔
220
    @Input()
3,368✔
221
    public set resourceStrings(value: ITreeResourceStrings) {
3,368✔
222
        this._resourceStrings = Object.assign({}, this._resourceStrings, value);
223
    }
224

225
    /**
226
     * An accessor that returns the resource strings.
227
     */
37,545✔
228
    public get resourceStrings(): ITreeResourceStrings {
229
        return this._resourceStrings;
230
    }
231

232
    /**
233
     * Gets/Sets the active state of the node
7,452✔
234
     *
235
     * @param value: boolean
236
     */
237
    @Input()
238
    public set active(value: boolean) {
239
        if (value) {
240
            this.navService.activeNode = this;
241
            this.tree.activeNodeBindingChange.emit(this);
242
        }
243
    }
244

245
    public get active(): boolean {
246
        return this.navService.activeNode === this;
247
    }
248

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

9✔
267
    /**
268
     * Emitted when the node's `expanded` property changes.
269
     *
270
     * ```html
118,403✔
271
     * <igx-tree>
272
     *      <igx-tree-node *ngFor="let node of data" [data]="node" [(expanded)]="node.expanded">
273
     *      </igx-tree-node>
1,629✔
274
     * </igx-tree>
76✔
275
     * ```
276
     *
277
     * ```typescript
1,553✔
278
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
279
     * node.expandedChange.pipe(takeUntil(this.destroy$)).subscribe((e: boolean) => console.log("Node expansion state changed to ", e))
280
     * ```
281
     */
282
    @Output()
37,545✔
283
    public expandedChange = new EventEmitter<boolean>();
284

285
    /** @hidden @internal */
286
    public get focused() {
287
        return this.isFocused &&
288
            this.navService.focusedNode === this;
289
    }
290

291
    /**
292
     * Retrieves the full path to the node incuding itself
293
     *
294
     * ```typescript
295
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
1,943✔
296
     * const path: IgxTreeNode<any>[] = node.path;
297
     * ```
298
     */
299
    public get path(): IgxTreeNode<any>[] {
3,359✔
300
        return this.parentNode?.path ? [...this.parentNode.path, this] : [this];
12✔
301
    }
302

3,359✔
303
    // TODO: bind to disabled state when node is dragged
3✔
304
    /**
3✔
305
     * Gets/Sets the disabled state of the node
3✔
306
     *
307
     * @param value: boolean
308
     */
309
    @Input()
310
    @HostBinding('class.igx-tree-node--disabled')
311
    public get disabled(): boolean {
312
        return this._disabled;
313
    }
314

315
    public set disabled(value: boolean) {
45!
316
        if (value !== this._disabled) {
×
317
            this._disabled = value;
318
            this.tree.disabledChange.emit(this);
45!
319
        }
×
320
    }
321

45✔
322
    /** @hidden @internal */
45✔
323
    @HostBinding('class.igx-tree-node')
1✔
324
    public cssClass = 'igx-tree-node';
1✔
325

326
    @HostBinding('style.--component-size')
44✔
327
    public get size(): string {
1✔
328
        switch(this.tree.displayDensity) {
1✔
329
            case DisplayDensity.compact:
330
                return 'var(--ig-size, var(--ig-size-small))';
331
            case DisplayDensity.cosy:
332
                return 'var(--ig-size, var(--ig-size-medium))';
333
            case DisplayDensity.comfortable:
334
            default:
335
                return 'var(--ig-size, var(--ig-size-large))';
336
        }
28✔
337
    }
338

339
    /** @hidden @internal */
340
    @HostBinding('attr.role')
341
    public get role() {
342
        return this.hasLinkChildren ? 'none' : 'treeitem';
343
    }
27✔
344

345
    /** @hidden @internal */
27✔
346
    @ContentChildren(IgxTreeNodeLinkDirective, { read: ElementRef })
2✔
347
    public linkChildren: QueryList<ElementRef>;
2✔
348

349
    /** @hidden @internal */
25✔
350
    @ContentChildren(IGX_TREE_NODE_COMPONENT, { read: IGX_TREE_NODE_COMPONENT })
9✔
351
    public _children: QueryList<IgxTreeNode<any>>;
352

353
    /** @hidden @internal */
16✔
354
    @ContentChildren(IGX_TREE_NODE_COMPONENT, { read: IGX_TREE_NODE_COMPONENT, descendants: true })
355
    public allChildren: QueryList<IgxTreeNode<any>>;
356

357
    /**
358
     * Return the child nodes of the node (if any)
359
     *
360
     * @remark
361
     * Returns `null` if node does not have children
362
     *
363
     * @example
364
     * ```typescript
365
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
366
     * const children: IgxTreeNode<any>[] = node.children;
367
     * ```
368
     */
369
    public get children(): IgxTreeNode<any>[] {
370
        return this._children?.length ? this._children.toArray() : null;
371
    }
372

11✔
373
    // TODO: will be used in Drag and Drop implementation
1✔
374
    /** @hidden @internal */
375
    @ViewChild('ghostTemplate', { read: ElementRef })
376
    public header: ElementRef;
10✔
377

378
    @ViewChild('defaultIndicator', { read: TemplateRef, static: true })
379
    private _defaultExpandIndicatorTemplate: TemplateRef<any>;
380

381
    @ViewChild('childrenContainer', { read: ElementRef })
9✔
382
    private childrenContainer: ElementRef;
9✔
383

384
    private get hasLinkChildren(): boolean {
385
        return this.linkChildren?.length > 0 || this.registeredChildren?.length > 0;
386
    }
387

388
    /** @hidden @internal */
23✔
389
    public get isCompact(): boolean {
23✔
390
        return this.tree?.displayDensity === DisplayDensity.compact;
391
    }
392

3,359✔
393
    /** @hidden @internal */
3,359✔
394
    public get isCosy(): boolean {
395
        return this.tree?.displayDensity === DisplayDensity.cosy;
396
    }
397

398
    /** @hidden @internal */
399
    public isFocused: boolean;
400

401
    /** @hidden @internal */
402
    public registeredChildren: IgxTreeNodeLinkDirective[] = [];
403

404
    /** @hidden @internal */
405
    private _resourceStrings = getCurrentResourceStrings(TreeResourceStringsEN);
406

407
    private _tabIndex = null;
408
    private _disabled = false;
409

410
    constructor(
411
        @Inject(IGX_TREE_COMPONENT) public tree: IgxTree,
25✔
412
        protected selectionService: IgxTreeSelectionService,
1✔
413
        protected treeService: IgxTreeService,
414
        protected navService: IgxTreeNavigationService,
24✔
415
        protected cdr: ChangeDetectorRef,
416
        @Inject(IgxAngularAnimationService) animationService: AnimationService,
417
        private element: ElementRef<HTMLElement>,
418
        @Optional() @SkipSelf() @Inject(IGX_TREE_NODE_COMPONENT) public parentNode: IgxTreeNode<any>
419
    ) {
24✔
420
        super(animationService);
24✔
421
    }
23✔
422

23✔
423
    /**
23✔
424
     * @hidden @internal
425
     */
426
    public get showSelectors() {
427
        return this.tree.selection !== IgxTreeSelectionType.None;
428
    }
429

430
    /**
431
     * @hidden @internal
432
     */
433
    public get indeterminate(): boolean {
434
        return this.selectionService.isNodeIndeterminate(this);
435
    }
436

437
    /** The depth of the node, relative to the root
438
     *
439
     * ```html
440
     * <igx-tree>
441
     *  ...
442
     *  <igx-tree-node #node>
6✔
443
     *      My level is {{ node.level }}
2✔
444
     *  </igx-tree-node>
445
     * </igx-tree>
4✔
446
     * ```
447
     *
448
     * ```typescript
449
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[12])[0];
450
     * const level: number = node.level;
4✔
451
     * ```
4✔
452
     */
3✔
453
    public get level(): number {
3✔
454
        return this.parentNode ? this.parentNode.level + 1 : 0;
455
    }
456

457
    /** Get/set whether the node is selected. Supporst two-way binding.
458
     *
15✔
459
     * ```html
15✔
460
     * <igx-tree>
461
     *  ...
462
     *  <igx-tree-node *ngFor="let node of data" [(selected)]="node.selected">
463
     *      {{ node.label }}
30✔
464
     *  </igx-tree-node>
30✔
465
     * </igx-tree>
15✔
466
     * ```
467
     *
468
     * ```typescript
2✔
469
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
470
     * const selected = node.selected;
471
     * node.selected = true;
472
     * ```
473
     */
474
    @Input()
475
    public get selected(): boolean {
476
        return this.selectionService.isNodeSelected(this);
477
    }
478

2✔
479
    public set selected(val: boolean) {
480
        if (!(this.tree?.nodes && this.tree.nodes.find((e) => e === this)) && val) {
481
            this.tree.forceSelect.push(this);
482
            return;
483
        }
484
        if (val && !this.selectionService.isNodeSelected(this)) {
485
            this.selectionService.selectNodesWithNoEvent([this]);
486
        }
487
        if (!val && this.selectionService.isNodeSelected(this)) {
488
            this.selectionService.deselectNodesWithNoEvent([this]);
489
        }
490
    }
491

492
    /** Get/set whether the node is expanded
493
     *
494
     * ```html
495
     * <igx-tree>
496
     *  ...
497
     *  <igx-tree-node *ngFor="let node of data" [expanded]="node.name === this.expandedNode">
498
     *      {{ node.label }}
499
     *  </igx-tree-node>
2✔
500
     * </igx-tree>
501
     * ```
502
     *
503
     * ```typescript
504
     * const node: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
505
     * const expanded = node.expanded;
506
     * node.expanded = true;
507
     * ```
508
     */
509
    @Input()
510
    public get expanded() {
511
        return this.treeService.isExpanded(this);
512
    }
513

514
    public set expanded(val: boolean) {
515
        if (val) {
516
            this.treeService.expand(this, false);
517
        } else {
518
            this.treeService.collapse(this);
519
        }
520
    }
521

522
    /** @hidden @internal */
523
    public get expandIndicatorTemplate(): TemplateRef<any> {
524
        return this.tree?.expandIndicator || this._defaultExpandIndicatorTemplate;
525
    }
526

527
    /**
528
     * The native DOM element representing the node. Could be null in certain environments.
529
     *
530
     * ```typescript
531
     * // get the nativeElement of the second node
532
     * const node: IgxTreeNode = this.tree.nodes.first();
533
     * const nodeElement: HTMLElement = node.nativeElement;
534
     * ```
535
     */
536
    /** @hidden @internal */
537
    public get nativeElement() {
538
        return this.element.nativeElement;
539
    }
540

541
    /** @hidden @internal */
542
    public ngOnInit() {
543
        this.openAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(
544
            () => {
545
                this.tree.nodeExpanded.emit({ owner: this.tree, node: this });
546
            }
547
        );
548
        this.closeAnimationDone.pipe(takeUntil(this.destroy$)).subscribe(() => {
549
            this.tree.nodeCollapsed.emit({ owner: this.tree, node: this });
550
            this.treeService.collapse(this);
551
            this.cdr.markForCheck();
552
        });
553
    }
554

555
    /**
556
     * @hidden @internal
557
     * Sets the focus to the node's <a> child, if present
558
     * Sets the node as the tree service's focusedNode
559
     * Marks the node as the current active element
560
     */
561
    public handleFocus(): void {
562
        if (this.disabled) {
563
            return;
564
        }
565
        if (this.navService.focusedNode !== this) {
566
            this.navService.focusedNode = this;
567
        }
568
        this.isFocused = true;
569
        if (this.linkChildren?.length) {
570
            this.linkChildren.first.nativeElement.focus();
571
            return;
572
        }
573
        if (this.registeredChildren.length) {
574
            this.registeredChildren[0].elementRef.nativeElement.focus();
575
            return;
576
        }
577
    }
578

579
    /**
580
     * @hidden @internal
581
     * Clear the node's focused status
582
     */
583
    public clearFocus(): void {
584
        this.isFocused = false;
585
    }
586

587
    /**
588
     * @hidden @internal
589
     */
590
    public onSelectorClick(event) {
591
        // event.stopPropagation();
592
        event.preventDefault();
593
        // this.navService.handleFocusedAndActiveNode(this);
594
        if (event.shiftKey) {
595
            this.selectionService.selectMultipleNodes(this, event);
596
            return;
597
        }
598
        if (this.selected) {
599
            this.selectionService.deselectNode(this, event);
600
        } else {
601
            this.selectionService.selectNode(this, event);
602
        }
603
    }
604

605
    /**
606
     * Toggles the node expansion state, triggering animation
607
     *
608
     * ```html
609
     * <igx-tree>
610
     *      <igx-tree-node #node>My Node</igx-tree-node>
611
     * </igx-tree>
612
     * <button type="button" igxButton (click)="node.toggle()">Toggle Node</button>
613
     * ```
614
     *
615
     * ```typescript
616
     * const myNode: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
617
     * myNode.toggle();
618
     * ```
619
     */
620
    public toggle() {
621
        if (this.expanded) {
622
            this.collapse();
623
        } else {
624
            this.expand();
625
        }
626
    }
627

628
    /** @hidden @internal */
629
    public indicatorClick() {
630
        this.toggle();
631
        this.navService.setFocusedAndActiveNode(this);
632
    }
633

634
    /**
635
     * @hidden @internal
636
     */
637
    public onPointerDown(event) {
638
        event.stopPropagation();
639
        this.navService.setFocusedAndActiveNode(this);
640
    }
641

642
    public override ngOnDestroy() {
643
        super.ngOnDestroy();
644
        this.selectionService.ensureStateOnNodeDelete(this);
645
    }
646

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

671
        };
672
        this.tree.nodeExpanding.emit(args);
673
        if (!args.cancel) {
674
            this.treeService.expand(this, true);
675
            this.cdr.detectChanges();
676
            this.playOpenAnimation(
677
                this.childrenContainer
678
            );
679
        }
680
    }
681

682
    /**
683
     * Collapses the node, triggering animation
684
     *
685
     * ```html
686
     * <igx-tree>
687
     *      <igx-tree-node #node>My Node</igx-tree-node>
688
     * </igx-tree>
689
     * <button type="button" igxButton (click)="node.collapse()">Collapse Node</button>
690
     * ```
691
     *
692
     * ```typescript
693
     * const myNode: IgxTreeNode<any> = this.tree.findNodes(data[0])[0];
694
     * myNode.collapse();
695
     * ```
696
     */
697
    public collapse() {
698
        if (!this.expanded || this.treeService.collapsingNodes.has(this)) {
699
            return;
700
        }
701
        const args: ITreeNodeTogglingEventArgs = {
702
            owner: this.tree,
703
            node: this,
704
            cancel: false
705

706
        };
707
        this.tree.nodeCollapsing.emit(args);
708
        if (!args.cancel) {
709
            this.treeService.collapsing(this);
710
            this.playCloseAnimation(
711
                this.childrenContainer
712
            );
713
        }
714
    }
715

716
    /** @hidden @internal */
717
    public addLinkChild(link: IgxTreeNodeLinkDirective) {
718
        this._tabIndex = -1;
719
        this.registeredChildren.push(link);
720
    }
721

722
    /** @hidden @internal */
723
    public removeLinkChild(link: IgxTreeNodeLinkDirective) {
724
        const index = this.registeredChildren.indexOf(link);
725
        if (index !== -1) {
726
            this.registeredChildren.splice(index, 1);
727
        }
728
    }
729
}
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