By default the ChipField can only show the content of a field, at least this is what the documentation tells. The example below displays the contents of the field name.
<ReferenceArrayField source="substances" reference="substances" label="Substanzen">
<SingleFieldList>
<ChipField source="name" />
</SingleFieldList>
</ReferenceArrayField>
However, I want ChipField to display a text combined of information from several fields:
const Substanz = ({ record }) => {
return record.name+" ("+record.unit+")";
};
<ReferenceArrayField source="substances" reference="substances" label="Substanzen">
<SingleFieldList>
<ChipField source={<Substanz />} /> <---- this does not work!
</SingleFieldList>
</ReferenceArrayField>
but unfortunately, source only accepts a field name, not an object like the OptionText prop of the SelectInput field.
What is the expected way to do this?
I think you are almost there with your custom SubstanzField component. Just use MUI styled component to make your own ChipField-like looking component and pass it directly inside of the SingleFieldList
MUI Chips docs
Don't know if you expected more sophisticated solution but this should be simple and flexible enough for your case.
Related
Our application uses "modals/dialogs" for editing form data and we're prototyping porting it over to React. I'm trying to design some reusable components for pieces of the modal UI.
I'm trying to design a ModalFooter component which always has an optional note about form fields being required, and some buttons to perform save, close, export, or various other actions. Because the buttons themselves vary modal-to-modal, I'm trying to allow those to passed.
The Button component is from the BlueprintJS library. I envision some kind of buttons prop that includes only Button type elements. Something more specific than children: JSX.Element[]. A button might look like this <Button onClick={save}>Save</Button>
I've seen a few very old approaches but am asking again as there may be newer features/approaches.
export type ModalFooterProps = {
buttons: Button[]
required: boolean
}
export const ModalFooter = ({ buttons, required }: ModalFooterProps) => (
<footer className={styles.footer}>
{ required ? '* Indicates required field' : '' }
{/* {buttons} */}
</footer>
)
This doesn't work, though. TypeScript throws an error that Button[] is unassignable to type ReactNode. I can't really use buttons.map because I don't have another element to map them to, I just need to print them as provided.
I would also prefer being able to use children so that the component using this would look something like this:
<ModalFooter required={true}>
<Button onClick={save}>Save</Button>
</ModalFooter>
Rather than this:
const buttons = [<Button onClick={save}>Save</Button>]
<ModalFooter buttons={buttons} required={true} />
Material UI's DataGrid's API shows how to add a sort icon when the direction is ascending and another one when the sort direction is descending. These default to the arrow up and arrow down icons and can easily be changed through props. My design requires to also have an icon when the sorting direction is null (i.e., the user hasn't clicked on that column header yet but the up-and-down arrows indicate that the column is sortable).
I have tried a couple of solutions but I'm not satisfied with any of them. I tried using renderHeader inside the ColDef to implement the icons when SortModel changes but it doesn't look good enough, plus the DataGrid layout gets messed up for some reason when SortModel is changed.
Is there a better way to simply add a sortable icon next to the header titles when no sorting direction is defined?
Material-UI DataGrid does not have an option to set the icon in no-sort state. To do that, you need to get your hands dirty.
I tried using renderHeader inside the ColDef to implement the icons when SortModel changes but it doesn't look good enough
In order to replicate the built-in sort icon, you need to know which components get rendered in the column header when in sorting mode. Having a look at the DataGrid source code, you can see that:
In GridColumnHeaderItem: If you don't provide renderHeader, it will render GridColumnHeaderTitle instead. So we need to use that component to render the header.
In GridColumnHeaderSortIcon: This component is used to render the sort icon, the icon is wrapped inside an IconButton with a small size that itself is wrapped inside a container. Make sure to copy that code when you render your own header icon.
Putting it together, we'll have something like below:
import { GridColumnHeaderTitle } from "#material-ui/x-grid";
{
field: "firstName",
headerName: "First name",
width: 130,
renderHeader: (params) => {
const { field, api, colDef } = params;
const sort = api.state.sorting.sortModel.filter(
(s) => s.field === field
)?.[0]?.sort;
const isSorting = Boolean(sort);
return (
<>
<GridColumnHeaderTitle
label={colDef.headerName || colDef.field}
description={colDef.description}
columnWidth={colDef.width}
/>
{!isSorting && (
<div className="MuiDataGrid-iconButtonContainer">
<IconButton size="small">
<ClearIcon className="MuiDataGrid-sortIcon" />
</IconButton>
</div>
)}
</>
);
}
},
Live Demo
I basically want to use react select with no options/dropdown (just like an input field) but use the multi feature available in select
so I figured something like this:
<Select
components={{ DropdownIndicator: () => null }}
placeholder="Start typing to enter options"
multi
/>
but this just gives me no options in the dropdown
how can I achieve this?
You might try adding an options={[]} prop, at least we achieve what you say doing that in our UI doing that. Adding some sort of "Add value" button input in the dropdown that enables the isMulti and then just passing the empty options.
https://react-select.com/props#prop-types
According to the oficial documentation, it is a valid approach.
When using the tag imported from reactstrap, I came across a minor problem.
I used
<.Input type="select" ... /.>
and wrapped inside it
<.option value={}....>
so that when an option was selected, the value of the input was set to the value of the selected option.
Even when the value of the Input tag was set with a number, accessing e.target.value provided me with a string, which I had to parse into an int.
So I was wondering if there is a specific return type for the Input tag of type select in reactstrap- even when the value is inputted as a number, does it automatically save it as a string?
It doesn't seem like there is a way to achieve this in reactstrap. However the beauty of React is that you are able to quickly write your own reusable component to achieve this.
const NumberSelect = (props) => (
<input type='select' onChange={(event) => {
props.onChange(parseInt(event.target.value, 10));
}}>
<option value={1}>One</option>
<option value={2}>Two</option>
</input>
);
You will need to tweak this code a bit according your own needs, but this is how I would solve your problem.
Please take a look at my code for Dropdown,
I'm using the semantic ui react dropdown on an EditProfile component. I have pasted a sample code here, https://codesandbox.io/s/m4288nx4z8, but I could not get it to work because I'm not very familiar with functional components in React, I've always used Class component. But you can check the full code for the whole component below in the github gist.
https://gist.github.com/mayordwells/b0cbb7b63af85269091f1f98296fd9bb
Please, I need help on inserting values from multiple select options of a Dropdown into the Database and also a way to display that back upon viewing the profile edit page again.
I'm using semantic-ui-react in react + rails app.
Also when I insert a value using a normal drop down without multiple select, the value gets persisted into the database.
<Dropdown
placeholder='Select Country'
fluid
search
selection
options={countryOptions}
name='country'
defaultValue={this.state.extraInfo.country}
onChange={(e) => this.handleExtraInfoChange('country', e)}
/>
This code handles change for the dropdown elements.
handleExtraInfoChange = (name, event) => {
let value;
if (event.target.value !== undefined) {
value = event.target.value;
} else {
value = event.target.textContent;
}
let newExtraInfo = Object.assign(this.state.extraInfo, { [name]: value })
this.setState({ extraInfo: newExtraInfo});
}
But when I visit the page again, I get a white blank in the input box. Here's a screen pic for that. When I comment out the defaultValue or value property(i have tried with defaultValue and value), the white blank disappears, but the value picked by a user is also not seen.
Please advice what is a possible solution to this misbehavior? And what is the best way to insert multiple values into the Database?
Thanks in advance for your time.
A functional component does not have state, it's used for composition; you want to store state, so you either have to create a Component class or you need an external state container like redux.