Skip to content

Commit be42109

Browse files
Introduce submit attribute to textbox
The implementation conditionally calls the keyup handler based on the values of the submit attribute. Fixes: #372
1 parent 6737d9f commit be42109

File tree

5 files changed

+33
-15
lines changed

5 files changed

+33
-15
lines changed

py/examples/textbox.py

+3-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
@app('/demo')
88
async def serve(q: Q):
9-
if q.args.show_inputs:
9+
if q.args.show_inputs or q.args.textbox_submit:
1010
q.page['example'].items = [
1111
ui.text(f'textbox={q.args.textbox}'),
1212
ui.text(f'textbox_disabled={q.args.textbox_disabled}'),
@@ -20,11 +20,7 @@ async def serve(q: Q):
2020
ui.text(f'textbox_placeholder={q.args.textbox_placeholder}'),
2121
ui.text(f'textbox_disabled_placeholder={q.args.textbox_disabled_placeholder}'),
2222
ui.text(f'textbox_multiline={q.args.textbox_multiline}'),
23-
ui.button(name='show_form', label='Back', primary=True),
24-
]
25-
elif q.args.enter_key_handler:
26-
q.page['example'].items = [
27-
ui.text(f'textbox_enter_key_handler={q.args.enter_key_handler}'),
23+
ui.text(f'textbox_enter={q.args.textbox_enter}'),
2824
ui.button(name='show_form', label='Back', primary=True),
2925
]
3026
else:
@@ -41,7 +37,7 @@ async def serve(q: Q):
4137
ui.textbox(name='textbox_placeholder', label='With placeholder', placeholder='I need some input'),
4238
ui.textbox(name='textbox_disabled_placeholder', label='Disabled with placeholder', disabled=True,
4339
placeholder='I am disabled'),
44-
ui.textbox(name='enter_key_handler', label='Submits the textbox value on Enter key', icon='Search'),
40+
ui.textbox(name='textbox_submit', label='Submits on enter pressed', icon='Search', submit=True),
4541
ui.textbox(name='textbox_multiline', label='Multiline textarea', multiline=True),
4642
ui.button(name='show_inputs', label='Submit', primary=True),
4743
])

py/h2o_wave/types.py

+7
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ def __init__(
946946
height: Optional[str] = None,
947947
visible: Optional[bool] = None,
948948
tooltip: Optional[str] = None,
949+
submit: Optional[bool] = None,
949950
):
950951
self.name = name
951952
"""An identifying name for this component."""
@@ -983,6 +984,8 @@ def __init__(
983984
"""True if the component should be visible. Defaults to true."""
984985
self.tooltip = tooltip
985986
"""An optional tooltip message displayed when a user clicks the help icon to the right of the component."""
987+
self.submit = submit
988+
"""True if the form should be submitted when enter key pressed."""
986989

987990
def dump(self) -> Dict:
988991
"""Returns the contents of this object as a dict."""
@@ -1007,6 +1010,7 @@ def dump(self) -> Dict:
10071010
height=self.height,
10081011
visible=self.visible,
10091012
tooltip=self.tooltip,
1013+
submit=self.submit,
10101014
)
10111015

10121016
@staticmethod
@@ -1032,6 +1036,7 @@ def load(__d: Dict) -> 'Textbox':
10321036
__d_height: Any = __d.get('height')
10331037
__d_visible: Any = __d.get('visible')
10341038
__d_tooltip: Any = __d.get('tooltip')
1039+
__d_submit: Any = __d.get('submit')
10351040
name: str = __d_name
10361041
label: Optional[str] = __d_label
10371042
placeholder: Optional[str] = __d_placeholder
@@ -1050,6 +1055,7 @@ def load(__d: Dict) -> 'Textbox':
10501055
height: Optional[str] = __d_height
10511056
visible: Optional[bool] = __d_visible
10521057
tooltip: Optional[str] = __d_tooltip
1058+
submit: Optional[bool] = __d_submit
10531059
return Textbox(
10541060
name,
10551061
label,
@@ -1069,6 +1075,7 @@ def load(__d: Dict) -> 'Textbox':
10691075
height,
10701076
visible,
10711077
tooltip,
1078+
submit,
10721079
)
10731080

10741081

py/h2o_wave/ui.py

+3
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ def textbox(
450450
height: Optional[str] = None,
451451
visible: Optional[bool] = None,
452452
tooltip: Optional[str] = None,
453+
submit: Optional[bool] = None,
453454
) -> Component:
454455
"""Create a text box.
455456
@@ -476,6 +477,7 @@ def textbox(
476477
height: The height of the text box, e.g. '100px'. Applicable only if `multiline` is true.
477478
visible: True if the component should be visible. Defaults to true.
478479
tooltip: An optional tooltip message displayed when a user clicks the help icon to the right of the component.
480+
submit: True if the form should be submitted when enter key pressed.
479481
Returns:
480482
A `h2o_wave.types.Textbox` instance.
481483
"""
@@ -498,6 +500,7 @@ def textbox(
498500
height,
499501
visible,
500502
tooltip,
503+
submit,
501504
))
502505

503506

ui/src/textbox.test.tsx

+16-6
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ describe('Textbox.tsx', () => {
102102
expect(syncMock).not.toBeCalled()
103103
})
104104

105-
it('Calls sync on enter pressed', () => {
106-
const { getByTestId } = render(<XTextbox model={textboxProps} />)
105+
it('Calls sync on enter pressed - submit specified', () => {
106+
const { getByTestId } = render(<XTextbox model={{ ...textboxProps, submit: true}} />)
107107
const syncMock = jest.fn()
108108

109109
T.qd.sync = syncMock
@@ -112,8 +112,8 @@ describe('Textbox.tsx', () => {
112112
expect(syncMock).toBeCalled()
113113
})
114114

115-
it('Does not call sync when key pressed is not enter', () => {
116-
const { getByTestId } = render(<XTextbox model={textboxProps} />)
115+
it('Does not call sync when key pressed is not enter - submit specified', () => {
116+
const { getByTestId } = render(<XTextbox model={{ ...textboxProps, submit: true}} />)
117117
const syncMock = jest.fn()
118118

119119
T.qd.sync = syncMock
@@ -122,8 +122,18 @@ describe('Textbox.tsx', () => {
122122
expect(syncMock).not.toBeCalled()
123123
})
124124

125-
it('Does not call sync on enter - multiline is true', () => {
126-
const { getByTestId } = render(<XTextbox model={{ ...textboxProps, multiline: true}} />)
125+
it('Does not call sync on enter pressed - submit not specified', () => {
126+
const { getByTestId } = render(<XTextbox model={textboxProps} />)
127+
const syncMock = jest.fn()
128+
129+
T.qd.sync = syncMock
130+
fireEvent.keyUp(getByTestId(name), { key: 'Enter', target: { value: 'text' } })
131+
132+
expect(syncMock).not.toBeCalled()
133+
})
134+
135+
it('Does not call sync on enter - multiline and submit both are true', () => {
136+
const { getByTestId } = render(<XTextbox model={{ ...textboxProps, multiline: true, submit: true}} />)
127137
const syncMock = jest.fn()
128138

129139
T.qd.sync = syncMock

ui/src/textbox.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ export interface Textbox {
6262
visible?: B
6363
/** An optional tooltip message displayed when a user clicks the help icon to the right of the component. */
6464
tooltip?: S
65+
/** True if the form should be submitted when enter key is pressed. */
66+
submit?: B
6567
}
6668

6769
const DEBOUNCE_TIMEOUT = 500
@@ -95,7 +97,7 @@ export const
9597
disabled={m.disabled}
9698
readOnly={m.readonly}
9799
onChange={m.trigger ? debounce(DEBOUNCE_TIMEOUT, onChange) : onChange}
98-
onKeyUp={onKeyUp}
100+
onKeyUp={m.submit ? onKeyUp: undefined}
99101
/>
100102
)
101103
: (
@@ -116,7 +118,7 @@ export const
116118
multiline={m.multiline}
117119
type={m.password ? 'password' : undefined}
118120
onChange={m.trigger ? debounce(DEBOUNCE_TIMEOUT, onChange) : onChange}
119-
onKeyUp={onKeyUp}
121+
onKeyUp={m.submit ? onKeyUp: undefined}
120122
/>
121123
)
122124

0 commit comments

Comments
 (0)