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

atinc / ngx-tethys / 90f0f0ed-223e-4754-9642-97b0660ce0dc

22 May 2025 02:22AM UTC coverage: 90.245% (-0.009%) from 90.254%
90f0f0ed-223e-4754-9642-97b0660ce0dc

Pull #3451

circleci

invalid-email-address
fix(property): remove oninit to subscribe click #TINFR-1760
Pull Request #3451: fix(property): remove oninit to subscribe click #TINFR-1760

5555 of 6826 branches covered (81.38%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

4 existing lines in 2 files now uncovered.

13696 of 14506 relevant lines covered (94.42%)

900.27 hits per line

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

92.31
/src/input/input-search.component.ts
1
import {
2
    AbstractControlValueAccessor,
3
    Constructor,
4
    mixinDisabled,
5
    mixinInitialized,
6
    mixinTabIndex,
7
    ThyCanDisable,
8
    ThyHasTabIndex,
9
    ThyInitialized,
10
    useHostFocusControl
11
} from 'ngx-tethys/core';
12

1✔
13
import {
14
    ChangeDetectionStrategy,
16✔
15
    Component,
16
    ElementRef,
17
    forwardRef,
1✔
18
    OnDestroy,
1✔
19
    OnInit,
20
    ViewEncapsulation,
21
    inject,
22
    input,
23
    effect,
24
    signal,
1✔
25
    output,
26
    viewChild
16✔
27
} from '@angular/core';
16✔
28
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
16✔
29
import { useHostRenderer } from '@tethys/cdk/dom';
16✔
30
import { ThyIcon } from 'ngx-tethys/icon';
16✔
31
import { ThyAutofocusDirective } from 'ngx-tethys/shared';
16✔
32
import { ThyInputDirective, ThyInputSize } from './input.directive';
16✔
33

16✔
34
import { FocusOrigin } from '@angular/cdk/a11y';
16✔
35
import { coerceBooleanProperty } from 'ngx-tethys/util';
16✔
36

16✔
37
export type ThyInputSearchTheme = 'default' | 'ellipse' | 'transparent' | '';
16✔
38
export type ThyInputSearchIconPosition = 'before' | 'after';
16✔
39

40
export const CUSTOM_INPUT_SEARCH_CONTROL_VALUE_ACCESSOR: any = {
13✔
41
    provide: NG_VALUE_ACCESSOR,
42
    useExisting: forwardRef(() => ThyInputSearch),
16✔
43
    multi: true
16✔
44
};
16✔
45

16✔
46
const noop = () => {};
16✔
47

48
const _MixinBase: Constructor<ThyHasTabIndex> &
16✔
49
    Constructor<ThyInitialized> &
16✔
50
    Constructor<ThyCanDisable> &
16✔
51
    typeof AbstractControlValueAccessor = mixinInitialized(mixinTabIndex(mixinDisabled(AbstractControlValueAccessor)));
52

53
/**
54
 * 搜索输入框
16✔
55
 * @name thy-input-search
16✔
56
 * @order 30
16!
UNCOV
57
 */
×
58
@Component({
59
    selector: 'thy-input-search',
16✔
60
    templateUrl: './input-search.component.html',
14✔
61
    providers: [CUSTOM_INPUT_SEARCH_CONTROL_VALUE_ACCESSOR],
6✔
62
    encapsulation: ViewEncapsulation.None,
63
    changeDetection: ChangeDetectionStrategy.OnPush,
64
    host: {
65
        class: 'thy-input form-control thy-input-search',
2!
66
        '[class.thy-input-search-ellipse]': 'thyTheme() === "ellipse"',
2✔
67
        '[class.thy-input-search-transparent]': 'thyTheme() === "transparent"',
2✔
68
        '[class.thy-input-search-before-with-clear]': 'searchText() && iconPosition() === "before"',
69
        '[class.form-control-active]': 'focused()',
70
        '[attr.tabindex]': 'tabIndex'
71
    },
72
    imports: [ThyIcon, ThyInputDirective, ThyAutofocusDirective, FormsModule]
73
})
34✔
74
export class ThyInputSearch extends _MixinBase implements ControlValueAccessor, OnInit, OnDestroy {
75
    private elementRef = inject(ElementRef);
76

17✔
77
    readonly inputElement = viewChild<ElementRef<any>>('input');
78

79
    private hostRenderer = useHostRenderer();
1✔
80

81
    private hostFocusControl = useHostFocusControl();
82

2✔
83
    public disabled = signal(false);
2✔
84

2✔
85
    searchText = signal<string>('');
2!
UNCOV
86

×
87
    focused = signal(false);
88

2✔
89
    /**
2✔
90
     * 搜索框 name 属性
2✔
91
     */
2✔
92
    readonly name = input('');
93

94
    /**
16✔
95
     * 搜索框 Placeholder
96
     */
1✔
97
    readonly placeholder = input('');
1✔
98

99
    /**
100
     * 搜索框风格
101
     * @type 'default' | 'ellipse' | 'transparent'
102
     * @default default
103
     */
104
    readonly thyTheme = input<ThyInputSearchTheme>();
105

106
    /**
107
     * 是否自动聚焦
108
     * @default false
109
     */
1✔
110
    readonly autoFocus = input(false, { alias: 'thySearchFocus', transform: coerceBooleanProperty });
111

112
    /**
113
     * 搜索图标位置,当传入 after 时,搜索图标在输入框后方显示,有内容时显示为关闭按钮
114
     * @type ThyInputSearchIconPosition
115
     */
116
    readonly iconPosition = input('before', {
117
        alias: 'thyIconPosition',
118
        transform: (value: ThyInputSearchIconPosition) => value || 'before'
119
    });
120

121
    /**
122
     * 输入框大小
123
     * @type 'xs' | 'sm' | 'md' | 'default' | 'lg'
124
     */
125
    readonly thySize = input<ThyInputSize>();
126

127
    /**
128
     * @deprecated please use thyClear
129
     */
130
    readonly clear = output<Event>();
131

132
    /**
133
     * 清除搜索事件
134
     */
135
    readonly thyClear = output<Event>();
136

137
    constructor() {
138
        super();
139

140
        effect(() => {
141
            this.focused.set(this.autoFocus());
142
        });
143

144
        effect(() => {
145
            const iconPosition = this.iconPosition();
146
            this.hostRenderer.updateClass([`thy-input-search-${iconPosition}`]);
147
        });
148
    }
149

150
    ngOnInit(): void {
151
        super.ngOnInit();
152

153
        this.hostFocusControl.focusChanged = (origin: FocusOrigin) => {
154
            if (this.disabled()) {
155
                return;
156
            }
157

158
            if (origin) {
159
                if (!this.focused()) {
160
                    this.inputElement().nativeElement.focus();
161
                }
162
            } else {
163
                if (this.focused()) {
164
                    this.focused.set(false);
165
                    this.onTouchedFn();
166
                }
167
            }
168
        };
169
    }
170

171
    writeValue(value: any): void {
172
        this.searchText.set(value);
173
    }
174

175
    setDisabledState?(isDisabled: boolean): void {
176
        this.disabled.set(isDisabled);
177
    }
178

179
    searchModelChange() {
180
        this.onChangeFn(this.searchText());
181
    }
182

183
    clearSearchText(event: Event) {
184
        const element = this.elementRef.nativeElement.querySelector('.input-search-control');
185
        element.focus();
186
        event.stopPropagation();
187
        if (this.disabled()) {
188
            return;
189
        }
190
        this.searchText.set('');
191
        this.onChangeFn(this.searchText());
192
        this.clear.emit(event);
193
        this.thyClear.emit(event);
194
    }
195

196
    ngOnDestroy(): void {
197
        this.hostFocusControl.destroy();
198
    }
199
}
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