Skip to content

[ISSUE-677] Helpertext on combobox #723

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 10, 2019
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/combobox/example/index.ts
Original file line number Diff line number Diff line change
@@ -65,7 +65,7 @@ export default class App extends WidgetBase {
private _value7 = '';
private _value8 = '';
private _value9 = '';
private _invalid = false;
private _valid = true;

onChange(value: string, key?: string) {
if (!key) {
@@ -89,7 +89,6 @@ export default class App extends WidgetBase {

render(): DNode {
const { onChange, onRequestResults } = this;

return v(
'div',
{
@@ -180,14 +179,18 @@ export default class App extends WidgetBase {
required: true,
onChange: (value: string) => {
this._value9 = value;
this._invalid = value.trim().length === 0;
this._valid = value.trim().length !== 0;
this.invalidate();
},
getResultLabel: (result: any) => result.value,
onRequestResults,
results: this._results,
value: this._value9,
invalid: this._invalid,
valid: { valid: this._valid, message: 'Please enter value of state' },
helperText: 'helper text',
onValidate: (valid: boolean | undefined, message: string) => {
console.log('onValidate called', valid, message);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this callback should be used to set valid back on the widget

Copy link
Author

@samends samends May 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the onValidate function do? I've been a bit confused there

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And if the onValidate function is something that will update the valid boolean based on the most up to date version of the dom shouldn't that be abstracted away so the user doesn't have to think about that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's a controlled component, the onValidate is a callback to inform the parent that the valid status has changed. It's upto the parent to set valid back on the widget so that it can display the new status.

},
inputProperties: {
placeholder: 'Enter a value'
}
60 changes: 49 additions & 11 deletions src/combobox/index.ts
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ import { CommonMessages, LabeledProperties } from '../common/interfaces';
import * as css from '../theme/combobox.m.css';
import * as baseCss from '../common/styles/base.m.css';
import { customElement } from '@dojo/framework/widget-core/decorators/customElement';
import HelperText from '../helper-text';

/**
* @type ComboBoxProperties
@@ -54,16 +55,18 @@ export interface ComboBoxProperties extends ThemedProperties, LabeledProperties,
getResultLabel?(result: any): DNode;
getResultSelected?(result: any): boolean;
getResultValue?(result: any): string;
helperText?: string;
widgetId?: string;
inputProperties?: TextInputProperties;
invalid?: boolean;
valid?: { valid?: boolean; message?: string; } | boolean;
isResultDisabled?(result: any): boolean;
onBlur?(value: string, key?: string | number): void;
onChange?(value: string, key?: string | number): void;
onFocus?(value: string, key?: string | number): void;
onMenuChange?(open: boolean, key?: string | number): void;
onRequestResults?(key?: string | number): void;
onResultSelect?(result: any, key?: string | number): void;
onValidate?: (valid: boolean | undefined, message: string) => void;
openOnFocus?: boolean;
readOnly?: boolean;
required?: boolean;
@@ -90,8 +93,9 @@ export enum Operation {
'clearable',
'disabled',
'inputProperties',
'invalid',
'valid',
'isResultDisabled',
'helperText',
'labelAfter',
'labelHidden',
'openOnFocus',
@@ -100,7 +104,7 @@ export enum Operation {
'results'
],
attributes: ['widgetId', 'label', 'value'],
events: ['onBlur', 'onChange', 'onFocus', 'onMenuChange', 'onRequestResults', 'onResultSelect']
events: ['onBlur', 'onChange', 'onFocus', 'onMenuChange', 'onRequestResults', 'onResultSelect', 'onValidate']
})
export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<ComboBoxProperties> {
private _activeIndex = 0;
@@ -290,32 +294,54 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
}

protected getRootClasses(): (string | null)[] {
const { clearable, invalid } = this.properties;
const {
clearable
} = this.properties;

const {
valid
} = this.validity;
const focus = this.meta(Focus).get('root');

return [
css.root,
this._open ? css.open : null,
clearable ? css.clearable : null,
focus.containsFocus ? css.focused : null,
invalid === true ? css.invalid : null,
invalid === false ? css.valid : null
valid === false ? css.invalid : null,
valid === true ? css.valid : null
];
}

protected get validity() {
const { valid = { valid: undefined, message: undefined } } = this.properties;

if (typeof valid === 'boolean') {
return { valid, message: undefined };
}

return {
valid: valid.valid,
message: valid.message
};
}

protected renderInput(results: any[]): DNode {
const {
classes,
disabled,
widgetId = this._idBase,
inputProperties = {},
invalid,
readOnly,
required,
value = '',
theme
theme,
helperText,
onValidate
} = this.properties;

const { valid, message } = this.validity;

return w(TextInput, {
...inputProperties,
key: 'textinput',
@@ -326,14 +352,16 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
: null,
autocomplete: 'list'
},
valid: typeof invalid === 'boolean' ? !invalid : undefined,
valid: { valid, message: this._open ? undefined : message },
disabled,
widgetId,
helperText: this._open ? undefined : helperText,
focus: this.shouldFocus,
onBlur: this._onInputBlur,
onFocus: this._onInputFocus,
onInput: this._onInput,
onKeyDown: this._onInputKeyDown,
onValidate,
readOnly,
required,
theme,
@@ -428,7 +456,6 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
const {
clearable = false,
widgetId = this._idBase,
invalid,
label,
readOnly,
required,
@@ -439,11 +466,22 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
theme,
classes
} = this.properties;

const {
valid
} = this.validity;

const { messages } = this.localizeBundle(commonBundle);
const focus = this.meta(Focus).get('root');

const menu = this.renderMenu(results);
this._onMenuChange();

if (results.length === 0 && this._open === true) {
this._open = false;
this.invalidate();
}

this._wasOpen = this._open;

const controls = [
@@ -456,7 +494,7 @@ export class ComboBox extends I18nMixin(ThemedMixin(FocusMixin(WidgetBase)))<Com
classes,
disabled,
focused: focus.containsFocus,
invalid,
invalid: !valid,
readOnly,
required,
hidden: labelHidden,
Loading