I have recently started learning React, and it's been very interesting. But after struggling for a few days on the following, I thought I'd see if someone wants to help me out and think along what I'm missing.
Application info
I am creating a React application (in front of a Java Spring Boot backend). I am using jhipster as code generator. Amongst others, it generates CRUD pages for entities. Let's say I have the two entities 'Character' and 'Item'. The Character entity has various fields that will store references to Items. There is a large number of Items. Form validation is done through availity-reactstrap-validation, and the original code was structured as a with various or components in between.
Intent
On the Character create/edit screen, I want to use a dropdown component that has server-side search on the Item collection, for each of the Item-related fields. Upon submission of the form, the values of the dropdowns should be saved in the Character instance.
Approaches taken - and problems encountered
I had found the very nice Dropdown component that supports server-side search, in semantic-ui-react. I have linked up the onSearchChange with the search backend of Item, and it works great: the Dropdown options are changed as I type. However, upon submission of the form, the Dropdown value is not part of the 'values' list, and thus it is not saved.
I think this is due to the fact that the Dropdown component is not an 'input', and definitely not an AvInput - and thus not recognised and available as 'value' in the saveEntity function.
I then tried to use AvInput with the tag={ItemDropdown} attribute. The 'tag' attribute allows to use a custom component for rendering the actual component. This seemed great on paper. But here the struggle with state/props started. In this setup, the AvItemDropdown is parent of a AvInput, which is the parent of a ItemDropdown of a Dropdown. Upon change of the ItemDropdown, the value is set properly in that state. However, the state of AvInput remains unchanged. And I think that state is used in the form submission. I have tried all sorts of 'hacky' things, based on blogs, SO posts, documentation - but I guess I just lack the understanding of how React works, or at least, with these specific packages.
Screenshot from Chrome DevTools React Components tree
Question How can I use the Dropdown component that I created, but somehow update the state of AvInput to make it work in this context of the form?
Code snippets
Form:
<AvForm model={characterEntity} onSubmit={saveEntity}>
<AvGroup>
<AvField id="character-item2" type="text" name="item2" /> // This works, as simple text input. Changed values here are saved properly. I want to replace this with the Dropdown component
</AvGroup>
<AvGroup>
<ItemDropdown /> // This was the first attempt. Working dropdown, but not saving
<AvItemDropdown name="item1" id="character-item1" /> // This is my second attempt, also not working
</AvGroup>
</AvForm>
SaveEntity:
const saveEntity = (event, errors, values) => {
console.log(values) //this
const entity = {
...characterEntity,
...values,
};
props.updateEntity(entity);
}
AvItemDropdown (in separate .tsx file):
class ItemDropdown extends Component {
state = {
isFetching: false,
value: "",
options: []
}
handleChange = (e, { value }) => {
this.setState({ value })
}
onSearchChange = (e, value) => {
axios.get(`/api/_search/items?query=${value.searchQuery}`)
.then((response) => {
const opts = []
_.forOwn(response.data, function(v, k) {
opts.push({key: v.id, text: v.name, value: v.name})
})
this.setState({options: opts})
})
}
render() {
const { isFetching, value, options } = this.state
return (
<Dropdown
fluid
selection
search
options={options}
value={value}
text={value}
placeholder='Select item'
onChange={this.handleChange}
onSearchChange={this.onSearchChange}
disabled={isFetching}
loading={isFetching}
/>
)
}
}
export default function AvItemDropdown (props) {
return <AvInput {...props} tag={ItemDropdown} />;
}
PS. this is my first question (yay community!) so please let me know if more/other info would be helpful.