React render a select field multiple times - javascript

I have 5 labels that I need to render and each of them should have a select field with these options: string, fixed, guid, disabled
I implemented the following code
class renderCampaignCodes extends Component {
state = {
defaultCampaigns: [
{ name: 'Campaign Source: utm_source' },
{ name: 'Campaign Medium: utm_medium' },
{ name: 'Campaign Name: utm_campaign' },
{ name: 'Campaign Term: utm_term' },
{ name: 'Campaign Content: utm_content' }
],
defaultTypes: ['string', 'fixed', 'guid', 'disabled']
}
render() {
const { defaultCampaigns } = this.state
return (
<Flexbox flexDirection='column' marginTop='20px' width='600px'>
{
defaultCampaigns.map((campaign, idx) => {
return (
<div key={idx}>
<Flexbox justifyContent='space-between'>
<Flexbox marginTop='40px'>
<label>{campaign.name}</label>
</Flexbox>
<Flexbox>
<Field
name='type'
component={renderSelectField}
label='Type'
children={this.state.defaultTypes.map((item, i) => <MenuItem
key={i}
value={item}
label={item.replace(/^\w/, l => l.toUpperCase())}
primaryText={item.replace(/^\w/, l => l.toUpperCase())}/>)
}
/>
</Flexbox>
</Flexbox>
</div>
)
})
}
</Flexbox>
)
}
}
But the selected value from any of the select fields will show up everywhere:
How can I prevent this from happening?

It looks like the name attribute for each of your selects is being set to the same, causing them all to take the same value from store/state (depending on your implementation).
You will want to namespace the type with something. For example:
<Field
name={`${idx}.type`}
component={renderSelectField}
label='Type'
children={this.state.defaultTypes.map((item, i) => (
<MenuItem
key={i}
value={item}
label={item.replace(/^\w/, l => l.toUpperCase())}
primaryText={item.replace(/^\w/, l => l.toUpperCase())}
/>
))}
/>

Related

ReactJs, TypeScript TypeError: menuItems.map is not a function, error on map

Hello I have the following logic of useState and map an array to display only one dropdownItems at a time
here i have my array with tags ( menu name, links ( to router), icon( menu icon), if have dropdown Items ( dropdown items))
my MenuTags:
export interface IDropdownItems {
Name: string;
Link: string;
}
export interface ITag {
Name: string;
Link: string;
Icon: IconType;
DropdownItems: IDropdownItems[] | null;
Active: boolean;
}
export const SideBarTags: ITag[] = [
{
Name: 'Tutoriais',
Link: '../tutorials',
Icon: GoBook,
DropdownItems: null,
Active: false,
},
{
Name: 'Avisos',
Link: '../news',
Icon: GoAlert,
DropdownItems: null,
Active: false,
},
{
Name: 'Serviços',
Link: '../services',
Icon: GoRocket,
Active: false,
DropdownItems: [
{ Name: 'Elo Boost', Link: '/eloBost' },
{ Name: 'Duo Boost', Link: '/duoBoost' },
{ Name: 'MD10', Link: '/eloBost' },
{ Name: 'Coaching', Link: '/duoBoost' },
{ Name: 'Vitóriais', Link: '/duoBoost' },
],
},
{
Name: 'Carteira',
Link: '../cartcredit',
Icon: FaCoins,
Active: false,
DropdownItems: [
{ Name: 'Histórico', Link: '/history' },
{ Name: 'Adicionar Crédito', Link: '/add' },
],
},
];
my MenuTag ( useState and map here ):
const MenuTags: React.FC<MenuTags> = ({ sideisOpen }) => {
const [menuItems, setMenuItems] = useState(SideBarTags);
return (
<MenuList open={sideisOpen}>
{menuItems.map((item, index) => (
<MenuTagsItems
key={item.Name}
Name={item.Name}
Active={item.Active}
DropdownItems={item.DropdownItems}
Icon={item.Icon}
Link={item.Link}
sideisOpened={sideisOpen}
tagFunction={setMenuItems}
/>
))}
</MenuList>
);
};
my MenuTagsItems
const MenuTagsItems: React.FC<ITag & IMenuTagsItems> = ({
sideisOpened,
Name,
Active,
DropdownItems,
Icon,
Link,
tagFunction,
}) => {
const clickHandler = (value) => () => {
console.log(value);
tagFunction((items) =>
items.map((item) => ({
...item,
Active: item.Name === value,
}))
);
};
return (
<ListItem>
<ListWrap
open={sideisOpened}
active={Active}
onClick={() => {
tagFunction(Name);
}}
>
<a>
<Icon size={18} />
<span className="li-name">{Name}</span>
</a>
</ListWrap>
{DropdownItems && (
<Drop
active={Active}
dropItems={DropdownItems}
Icon={Icon}
isOpen={sideisOpened}
setVisible={tagFunction}
/>
)}
</ListItem>
);
};
and if menu tag have dropdown items
my DropDown:
const Drop: React.FC<IDrop> = ({
active,
isOpen,
dropItems,
setVisible,
Icon,
}) => {
return (
<OpenedStyled active={active}>
{dropItems.map((item) => (
<li className="li-open" key={item.Name}>
<Icon />
<a>{item.Name}</a>
</li>
))}
</OpenedStyled>
);
};
sorry i forgot error
i got this error:
Uncaught TypeError: menuItems.map is not a function
here:
<MenuList open={sideisOpen}>
{menuItems.map((item, index) => (
<MenuTagsItems
key={item.Name}
Name={item.Name}
Active={item.Active}
DropdownItems={item.DropdownItems}
Icon={item.Icon}
Link={item.Link}
sideisOpened={sideisOpen}
tagFunction={setMenuItems}
/>
))}
</MenuList>
It looks like a problem is here:
<ListWrap
open={sideisOpened}
active={Active}
onClick={() => {
tagFunction(Name);
}}
>
More specific, you are calling tagFunction (which is setMenuItems) in onClick handler with a Name parameter that is not an array, and you are setting it for menuItems state. Since it's not an array it doesn't have map, so there is an error.
Similar potential error you might have here:
<Drop
active={Active}
dropItems={DropdownItems}
Icon={Icon}
isOpen={sideisOpened}
setVisible={tagFunction}
/>
with setVisible param, but I see it's not used in a Component yet.

Conditional rendering does not display my data properly

I have a component to display data on a material-ui table called UserRow.
This component is used on another component called users.
But in order to display the data properly in each field the only way I found was to create a conditional rendering, so i could just render the data that i wanted in each field, otherwise it would be duplicated.
Is there a way to just call once the <UserRow/> component and get the same results as i get in the image bellow?
UserRow:
export default function UserRow( props, {name, details}) {
const style = styles();
function UserName(props) {
const showUserRow = props.showUserRow;
if (showUserRow) {
return <ListItem>
<ListItemIcon >
<PeopleIcon className={style.iconColor}/>
</ListItemIcon>
<ListItemText className={style.text}>{props.userRow}</ListItemText>
</ListItem>
}
return<div></div>;
}
function IconDetails(props) {
const showDetailsRow = props.showDetailsRow;
if (showDetailsRow) {
return <Link to={`/users/${props.detailsRow}`}>
<ListItemIcon >
<ListAltIcon className={style.iconColor}/>
</ListItemIcon>
</Link>;
}
return<div></div>;
}
return (
<List>
<ListItem>
<UserName userRow={props.name} showUserRow={props.showUserRow}/>
<IconDetails detailsRow={props.details} showDetailsRow={props.showDetailsRow}/>
</ListItem>
</List>
)
}
users:
export default function User({ data }) {
const style = styles();
const userList = data.map((row) => {
return { name: row, details: row };
});
const [state] = React.useState({
users: [
...userList,
]
});
return (
<div>
<MaterialTable
icons={tableIcons}
title={<h1 className={style.title}>Users</h1>}
columns={[
{
title: "Name",
field: "name",
render: rowData => (
<UserRow showUserRow={true} showDetailsRow={false} name={rowData.name} />
)
},
{
title: "Details",
field: "details",
render: rowData => (
<UserRow showUserRow={false} showDetailsRow={true} details={rowData.details} />
)
},
]}
data={state.users}
options={{
search: true
}}
/>
</div>
)
}
What i had before:
UserRow:
export default function UserRow( props, {name, details}) {
const style = styles();
return (
<List>
<ListItem>
<ListItemIcon >
<PeopleIcon className={style.color}/>
</ListItemIcon>
<ListItemText className={style.text}>{name}</ListItemText>
<Link to={`/users/${details}`}>
<ListItemIcon >
<ListAltIcon className={style.iconColor}/>
</ListItemIcon>
</Link>
</ListItem>
</List>
)
}
users:
return (
<div>
<MaterialTable
icons={tableIcons}
title={<h1 className={style.title}>Users</h1>}
columns={[
{
title: "Name",
field: "name",
render: rowData => (
<UserRow name={rowData.name} details={rowData.details} />
)
},
{
title: "Details",
},
]}
data={state.users}
options={{
search: true
}}
/>
</div>
)
}
The problem here, in the previous solution, is that if we create a title Details, the material-ui table creates a div for the details and I can't place my icon there, and this would be a problem if i had more data and need to place the data in the respective position.
What i was trying to achieve with the previous solution was to cut down some code, because if i have many fields i will repeat too much code.
Link that might be useful: https://material-table.com/#/docs/get-started

Custom SingleValue and Option react-select - Option displays, but SingleValue doesn't

I'm trying to create a custom Select using react-select. I want to create a custom Option and SingleValue. The custom Option renders, but SingleValue doesn't. The single value (selected value) displays as per the default styling.
Here's my code,
const Option = (props) => {
const { data, innerProps, innerRef, cx, getStyles, className } = props;
const [hover, setHover] = useState(false);
return (
<div ref={innerRef} {...innerProps}
style={getStyles('option', props)}
className={cx(
{
option: true,
},
className
)}
>
<div style={{ marginLeft: 10}} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}>
<p> {data.label} </p>
{ hover ? <Alert bsStyle="success" style={{ opacity: 0.8 }}>
<p> {data.description} </p>
</Alert> : null}
</div>
</div>
)
};
I have tried SingleValue like this,
const SingleValue = ({
cx,
getStyles,
selectProps,
data,
isDisabled,
className,
...props
}) => {
console.log(props);
return (
<div
className={cx(
emotionCss(getStyles("singleValue", props)),
{
"single-value": true,
"single-value--is-disabled": isDisabled
},
className
)}
>
<div>{data.label}</div>
<div style={{ fontSize: "10px" }}>{data.description}</div>
</div>
);
};
And this,
const SingleValue = props => (
<components.SingleValue {...props}>
{props.data.description}
</components.SingleValue>
);
I render it like this,
<Select
id="color"
options={this.props.options}
isMulti={true}
onChange={this.handleChange}
onBlur={this.handleBlur}
value={this.props.value}
components={{ Option, SingleValue }}
/>
Both ways of SingleValue don't work. I have tried to just include SingleValue in components, but that also does't work. Could anyone please help? Thanks!
I had the same problem and I solved it using components.ValueContainer instead of components.SingleValue. In my case, I used react-select to have an icon select component.
This is my constructor:
constructor(props) {
super(props);
this.state = {
icons: [{label: "temperature-low", value: "temperature-low", icon: "temperature-low"}, {label: "utensils", value: "utensils", icon: "utensils"}, {label: "venus", value: "venus", icon: "venus"}, {label: "volume-up", value: "volume-up", icon: "volume-up"}, {label: "wifi", value: "wifi", icon: "wifi"}],
inputValueIcon: "",
};
this.handleChangeIcon = this.handleChangeIcon.bind(this);
}
This is my handleChange function:
handleChangeIcon(selectedItem) {
this.setState({
inputValueIcon: selectedItem
})
}
And finally, my render function:
render() {
const { Option, ValueOption, ValueContainer } = components;
const IconOption = (props) => (
<Option {...props}>
<MDBIcon icon={props.data.label} />
</Option>
);
const ValueOptionLabel = (props) => (
<ValueContainer {...props}>
<MDBIcon icon={props.data.label} />
</ValueContainer>
);
return(
<Fragment>
<Select
placeholder="Select an icon"
value={this.state.inputValueIcon}
onChange={ this.handleChangeIcon }
components={{ Option: IconOption, SingleValue: ValueOptionLabel }}
options={ this.state.icons }
/>
</Fragment>
);
}
It's not the best solution, but it works :)

React Autocomplete

React_autosuggestion did not show suggestions while typing on input box
even though the same code is copy pasted from documentation react-autosuggestion upi.
<ReactAutocomplete
items={[
{ id: 'foo', label: 'foo' },
{ id: 'bar', label: 'bar' },
{ id: 'baz', label: 'baz' },
]}
shouldItemRender={(item, value) => item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
getItemValue={item => item.label}
renderItem={(item, highlighted) =>
<div
key={item.id}
style={{ backgroundColor: highlighted ? '#eee' : 'transparent'}} >
{item.label}
</div>
}
value={value}
onChange={e => setCurrentValue( e.target.value )}
onSelect={value => setCurrentValue( value )}
/>
imported as:
import ReactAutocomplete from 'react-autocomplete';
and the value is declared and set using a function:
const [value,setValue]=useState('');
const setCurrentValue=(value)=>{
console.log('hhhh',value)
setValue(value);
}
However, as shown in the screenshot below, the suggestion is not displayed.

ReactJS , How to change form type, from onChange dropdown

I'm learning ReactJS, I have dropdown from semantic-ui , and I want it to add onChange event on it. when dropdown change, the form below also change. is it possible? anyone know how to do it?
this is my code.
layout
class EditForm extends React.Component {
componentWillMount() {
this.setState({
options: [
{ key: 1, text: 'Input', value: '1' },
{ key: 2, text: 'Dropdown', value: '2' },
{ key: 3, text: 'Radio Boxes', value: '3' },
{ key: 4, text: 'Checkboxes', value: '4' },
{ key: 5, text: 'Paragraph', value:'5'},
],
selected: ['0'],
});
}
handleChange = (e, { value }) => this.setState({
value
})
render() {
const { value } = this.state
return(
<Segment clearing>
<Container textAlign='right'>
<Dropdown selection
onChange={this.handleChange}
options={this.state.options}
value={value}
defaultValue={this.state.selected}
/>
</Container>
<Form.Group widths='equal'>
<Form.Field>
<Input
style={{width:'480px'}}
/>
</Form.Field>
<Form.Field >
<Button animated='vertical' floated='right' >
<Button.Content hidden>Delete</Button.Content>
<Button.Content visible>
<Icon name='trash outline' />
</Button.Content>
</Button>
<Button animated='vertical' floated='right'>
<Button.Content hidden>Copy</Button.Content>
<Button.Content visible>
<Icon name='copy' />
</Button.Content>
</Button>
</Form.Field>
</Segment>
);
export default EditForm;
I want it to change depending on selected value. if dropdown is selected. than the dropdown form appear. and so on.
is it possible? what is the best way to do it? Thanks.
You can work with conditional rendering where you check for a specific condition before render your component.
Something as:
render() {
const { value } = this.state
return (
<div>
{value === 'dropdown' && <Component1>...</Component1>}
{value === 'text' && <Component2></Component2>}
{value === 'checkboxes' && <Component3></Component3>}
...
</div>
)
}

Categories

Resources