Last active
April 20, 2021 13:30
-
-
Save solace/5bf893ef71f6ce8dbdf674e3aca17dda to your computer and use it in GitHub Desktop.
Use react-bootstrap-typeahead with react-bootstrap-table
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import editor from 'react-bootstrap-table/lib/Editor'; | |
// Copied wholesale from react-bootstrap-table, modified where noted | |
class CustomModalBody extends React.Component { | |
getFieldValue() { | |
const newRow = {}; | |
this.props.columns.forEach((column, i) => { | |
let inputVal; | |
if (column.autoValue) { | |
// when you want same auto generate value and not allow edit, example ID field | |
const time = new Date().getTime(); | |
inputVal = typeof column.autoValue === 'function' ? | |
column.autoValue() : | |
(`autovalue-${time}`); | |
} else if (column.hiddenOnInsert || !column.field) { | |
inputVal = ''; | |
} else { | |
// CHANGE: Not using `refs` syntax, omitted the counter. | |
// Add the counter back if there is risk of duplicate fields. | |
const dom = this[column.field]; | |
inputVal = dom.value; | |
if (column.editable && column.editable.type === 'checkbox') { | |
const values = inputVal.split(':'); | |
inputVal = dom.checked ? values[0] : values[1]; | |
} else if (column.customInsertEditor) { | |
inputVal = inputVal || dom.getFieldValue(); | |
} | |
} | |
newRow[column.field] = inputVal; | |
}, this); | |
return newRow; | |
} | |
render() { | |
const { columns, validateState, ignoreEditable } = this.props; | |
return ( | |
<div className='modal-body'> | |
{ | |
columns.map((column, i) => { | |
const { | |
editable, | |
format, | |
field, | |
name, | |
autoValue, | |
hiddenOnInsert, | |
customInsertEditor | |
} = column; | |
const attr = { | |
// CHANGE: Use function ref instead. | |
// If using field index above, apply here as well | |
ref: (ref) => { | |
this[field] = field === 'name' && ref && ref.instanceRef ? ref.instanceRef : ref; | |
}, | |
placeholder: editable.placeholder ? editable.placeholder : name | |
}; | |
let fieldElement; | |
const defaultValue = editable.defaultValue || undefined; | |
if (customInsertEditor) { | |
const { getElement } = customInsertEditor; | |
fieldElement = getElement(column, attr, 'form-control', ignoreEditable, defaultValue); | |
} | |
// fieldElement = false, means to use default editor when enable custom editor | |
// Becasuse some users want to have default editor based on some condition. | |
if (!customInsertEditor || fieldElement === false) { | |
fieldElement = editor(editable, attr, format, '', defaultValue, ignoreEditable); | |
} | |
if (autoValue || hiddenOnInsert || !column.field) { | |
// when you want same auto generate value | |
// and not allow edit, for example ID field | |
return null; | |
} | |
const error = validateState[field] ? | |
(<span className='help-block bg-danger'>{ validateState[field] }</span>) : | |
null; | |
return ( | |
<div className='form-group' key={ field }> | |
<label>{ name }</label> | |
{ fieldElement } | |
{ error } | |
</div> | |
); | |
}) | |
} | |
</div> | |
); | |
} | |
} | |
export default CustomModalBody; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { Typeahead, asyncContainer } from 'react-bootstrap-typeahead'; | |
// Install this so that you can remove editable mode from the custom field | |
import onClickOutside from 'react-onclickoutside'; | |
const AsyncTypeahead = asyncContainer(Typeahead); | |
class CustomTypeaheadField extends React.Component { | |
constructor(props) { | |
super(props); | |
this.updateState = this.updateState.bind(this); | |
this.updateData = this.updateData.bind(this); | |
this.state = { | |
name: props.defaultValue, | |
isLoading: false, | |
options: [] | |
} | |
} | |
// From react-onclickoutside, this is your manual 'saveOnBlur' handling | |
// that would otherwise be done by the table that also deselects the field | |
handleClickOutside(e) { | |
try { | |
if (this.props.tableRef) { | |
this.updateData(); | |
this.props.tableRef.cleanSelected(); | |
} | |
} catch (e) {} | |
} | |
focus() { | |
this._typeahead.getInstance().focus(); | |
} | |
getFieldValue() { | |
return this.state.name; | |
} | |
updateData() { | |
this.props.onUpdate(this.state.name); | |
} | |
// Update internal state instead of whatever handler/redux action you would have used. | |
// Note: typeahead onChange returns an array, or empty array on clear, handle as needed | |
updateState(values) { | |
let value = ''; | |
if (values.length > 0) { | |
value = values[0]; | |
} | |
this.setState({name: value}); | |
} | |
render() { | |
return <div> | |
<AsyncTypeahead | |
innerRef={ref => this._typeahead = ref} | |
allowNew={true} | |
clearButton={true} | |
isLoading={this.state.isLoading} | |
labelKey={'name'} | |
onSearch={query => { | |
this.setState({isLoading: true}); | |
let URL = 'REMOTE'; | |
fetch(URL) | |
.then(res => res.json()) | |
.then(json => { | |
this.setState({isLoading: false, options: json}); | |
}); | |
}} | |
options={this.state.options} | |
// defaultSelected instead of selected, can't use it controlled in a table | |
defaultSelected={[this.props.defaultValue]} | |
onChange={this.updateState} | |
/> | |
</div>; | |
} | |
} | |
export default onClickOutside(CentreAgentNameField); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import styled from 'styled-components'; | |
import { BootstrapTable as UnstyledBootstrapTable, TableHeaderColumn } from 'react-bootstrap-table'; | |
import CustomTypeaheadField from './CustomTypeaheadField'; | |
import CustomModalBody from './CustomModalBody'; | |
// Resolves typeahead suggestions disappearing inside field borders | |
const BootstrapTable = styled(UnstyledBootstrapTable)` | |
& .react-bs-container-body { | |
overflow: inherit !important; | |
} | |
& td.typeahead-cell { | |
overflow: inherit !important; | |
} | |
`; | |
class ViewComponent extends React.Component { | |
constructor(props) { | |
this.createCustomEditField = this.createCustomEditField.bind(this); | |
this.createCustomInsertField = this.createCustomInsertField.bind(this); | |
} | |
createCustomModalBody(columns, validateState, ignoreEditable) { | |
return ( | |
<CustomModalBody | |
columns={ columns } | |
validateState={ validateState } | |
ignoreEditable={ ignoreEditable } | |
/> | |
); | |
} | |
createCentreAgentNameEditField(onUpdate, props) { | |
return <CustomTypeaheadField onUpdate={onUpdate} {...props} tableRef={this._bootstraptable} />; | |
} | |
createCentreAgentNameInsertField(column, attr, editorClass, ignoreEditable) { | |
return <CustomTypeaheadField {...attr} />; | |
} | |
render() { | |
return <BootstrapTable | |
// Need this for the onBlur handling for the custom field | |
ref={ref => this._bootstraptable = ref} | |
data={ data } | |
remote={ true } | |
insertRow={ true } | |
deleteRow={ true } | |
selectRow={ { mode: 'radio' } } | |
cellEdit={{ | |
mode: 'click', | |
blurToSave: true, | |
afterSaveCell: updateHandler | |
}} | |
options={{ | |
// Override insert modal body | |
insertModalBody: this.createCustomModalBody, | |
onAddRow: addHandler, | |
onDeleteRow: removeHandler | |
}} | |
> | |
<TableHeaderColumn dataField='id' isKey={ true } autoValue={ true }>ID</TableHeaderColumn> | |
<TableHeaderColumn | |
dataField='name' | |
// Typeahead suggestions disappearing behind cell borders | |
editColumnClassName='typeahead-cell' | |
// Custom typeahead fields | |
customEditor={ { getElement: this.createCustomEditField } } | |
customInsertEditor={ { getElement: this.createCustomInsertField } } | |
editable={ { readOnly: false } } | |
> | |
Name | |
</TableHeaderColumn> | |
... | |
</BootstrapTable> | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment