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

atinc / ngx-tethys / #55

30 Jul 2025 07:08AM UTC coverage: 9.866% (-80.4%) from 90.297%
#55

push

why520crazy
feat(empty): add setMessage for update display text #TINFR-2616

92 of 6794 branches covered (1.35%)

Branch coverage included in aggregate %.

2014 of 14552 relevant lines covered (13.84%)

6.15 hits per line

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

3.66
/src/tree/tree-node.component.ts
1
import {
2
    Component,
3
    ElementRef,
4
    TemplateRef,
5
    ViewEncapsulation,
6
    numberAttribute,
7
    inject,
8
    input,
9
    computed,
10
    contentChild,
11
    viewChild,
12
    output
13
} from '@angular/core';
14

15
import { THY_TREE_ABSTRACT_TOKEN } from './tree-abstract';
16
import { ThyTreeNode } from './tree.class';
17
import { ThyTreeEmitEvent, ThyTreeNodeCheckState, ThyClickBehavior } from './tree.class';
1✔
18
import { ThyTreeService } from './tree.service';
19
import { ThyLoading } from 'ngx-tethys/loading';
×
20
import { ThyIcon } from 'ngx-tethys/icon';
×
21
import { NgClass, NgStyle, NgTemplateOutlet } from '@angular/common';
×
22
import { coerceBooleanProperty } from 'ngx-tethys/util';
×
23

×
24
/**
×
25
 * 树形控件的节点组件
×
26
 * @private
×
27
 * @name thy-tree-node
×
28
 */
×
29
@Component({
×
30
    selector: 'thy-tree-node',
×
31
    templateUrl: './tree-node.component.html',
×
32
    encapsulation: ViewEncapsulation.None,
×
33
    imports: [ThyIcon, NgClass, NgStyle, NgTemplateOutlet, ThyLoading],
×
34
    host: {
×
35
        '[class.thy-tree-node]': 'true',
×
36
        '[class]': 'itemClass()'
×
37
    }
×
38
})
×
39
export class ThyTreeNodeComponent {
×
40
    root = inject(THY_TREE_ABSTRACT_TOKEN);
41
    thyTreeService = inject(ThyTreeService);
×
42

×
43
    /**
44
     * node 节点展现所需的数据
×
45
     */
×
46
    readonly node = input<ThyTreeNode>(null);
47

×
48
    /**
49
     * 设置 TreeNode 是否支持异步加载
50
     */
×
51
    readonly thyAsync = input(false, { transform: coerceBooleanProperty });
×
52

×
53
    /**
54
     * 设置 TreeNode 是否支持多选节点
55
     */
×
56
    readonly thyMultiple = input(false, { transform: coerceBooleanProperty });
×
57

58
    /**
59
     * 设置 TreeNode 是否支持拖拽排序
×
60
     */
×
61
    readonly thyDraggable = input(false, { transform: coerceBooleanProperty });
62

63
    /**
×
64
     * 设置 TreeNode 是否支持 Checkbox 选择
65
     */
66
    readonly thyCheckable = input(false, { transform: coerceBooleanProperty });
67

×
68
    /**
69
     * 点击节点的行为,`default` 为选中当前节点,`selectCheckbox` 为选中节点的 Checkbox, `thyCheckable` 为 true 时生效。
70
     * @default default
71
     */
72
    readonly thyClickBehavior = input<ThyClickBehavior>(undefined);
73

74
    /**
×
75
     * 设置节点名称是否支持超出截取
76
     * @default false
77
     */
78
    readonly thyTitleTruncate = input(false, { transform: coerceBooleanProperty });
79

80
    /**
81
     * 设置 TreeNode 的渲染模板
×
82
     */
×
83
    readonly templateRef = input<TemplateRef<any>>();
×
84

×
85
    /**
86
     * 设置子的空数据渲染模板
×
87
     */
×
88
    readonly emptyChildrenTemplateRef = input<TemplateRef<any>>();
89

×
90
    /**
×
91
     * 设置 node 点击事件
×
92
     */
×
93
    readonly thyOnClick = output<ThyTreeEmitEvent>();
×
94

95
    /**
96
     * 双击 node 事件
×
97
     */
98
    readonly thyDblClick = output<ThyTreeEmitEvent>();
99

×
100
    /**
101
     * 点击展开触发事件
102
     */
103
    readonly thyOnExpandChange = output<ThyTreeEmitEvent>();
104

105
    /**
106
     * 设置 check 选择事件
×
107
     */
×
108
    readonly thyOnCheckboxChange = output<ThyTreeEmitEvent>();
×
109

×
110
    /**
×
111
     * 设置 childrenTree 的渲染模板
112
     */
113
    readonly childrenTreeTemplateRef = contentChild<TemplateRef<any>>('childrenTree');
114

115
    /** The native `<div class="thy-tree-node-wrapper thy-sortable-item"></div>` element. */
×
116
    readonly treeNodeWrapper = viewChild<ElementRef<HTMLElement>>('treeNodeWrapper');
×
117

118
    /**
119
     * 开启虚拟滚动时,单行节点的高度,当`thySize`为`default`时,该参数才生效
120
     */
121
    readonly thyItemSize = input(44, { transform: numberAttribute });
×
122

123
    /**
1✔
124
     * 设置节点缩进距离,缩进距离 = thyIndent * node.level
125
     */
126
    readonly thyIndent = input(25, { transform: numberAttribute });
127

128
    readonly nodeIcon = computed(() => {
129
        return this.node().origin.icon;
130
    });
131

132
    readonly nodeIconStyle = computed(() => {
133
        return this.node().origin.iconStyle;
134
    });
135

136
    protected readonly itemClass = computed(() => {
137
        return this.node()?.itemClass?.join(' ');
138
    });
139

140
    checkState = ThyTreeNodeCheckState;
141

142
    public clickNode(event: Event) {
143
        const node = this.node();
1✔
144
        if (node.isDisabled) {
145
            this.expandNode(event);
146
        } else {
147
            if (this.thyCheckable() && this.thyClickBehavior() === 'selectCheckbox') {
148
                this.clickNodeCheck(event);
149
            } else {
150
                if (this.root.thyMultiple()) {
151
                    this.root.toggleTreeNode(node);
152
                } else {
153
                    this.root.selectTreeNode(node);
154
                }
155
            }
156
        }
157
        this.thyOnClick.emit({
158
            eventName: 'click',
159
            event: event,
160
            node: node
161
        });
162
    }
163

164
    public dbClickNode(event: Event) {
165
        this.thyDblClick.emit({
166
            eventName: 'dbclick',
167
            event: event,
168
            node: this.node()
169
        });
170
    }
171

172
    public clickNodeCheck(event: Event) {
173
        event.stopPropagation();
174
        const node = this.node();
175
        if (node.isChecked === ThyTreeNodeCheckState.unchecked) {
176
            node.setChecked(true);
177
        } else if (node.isChecked === ThyTreeNodeCheckState.checked) {
178
            node.setChecked(false);
179
        } else if (node.isChecked === ThyTreeNodeCheckState.indeterminate) {
180
            if (node.children?.length) {
181
                const activeChildren = node.children.filter(item => !item.isDisabled);
182
                const isAllActiveChildrenChecked = activeChildren.every(item => item.isChecked);
183
                node.setChecked(!isAllActiveChildrenChecked);
184
            } else {
185
                node.setChecked(true);
186
            }
187
        }
188
        this.thyOnCheckboxChange.emit({
189
            eventName: 'checkboxChange',
190
            event: event,
191
            node: node
192
        });
193
    }
194

195
    public expandNode(event: Event) {
196
        event.stopPropagation();
197
        const node = this.node();
198
        this.node().setExpanded(!node.isExpanded);
199
        if (this.root.thyShowExpand()) {
200
            this.thyOnExpandChange.emit({
201
                eventName: 'expand',
202
                event: event,
203
                node: node
204
            });
205
            if (this.thyAsync() && node.children.length === 0) {
206
                node.setLoading(true);
207
            }
208
        }
209
    }
210

211
    public isShowExpand(node: ThyTreeNode) {
212
        return this.root.isShowExpand(node);
213
    }
214
}
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

© 2025 Coveralls, Inc