Manage Input inside a List in React - reactjs

I call a GET from a server and this request return an array of N objects. Then on this array I generate a List using Antd in this way:
render() {
return (
<List
dataSource={this.props.images}
renderItem={image => (
<List.Item actions={
[
<Icon key={"1"+image.Id.toString()} onClick={(e) => this.actionClick('RUN',image.Id, image.RepoTags[0].replace(/[^a-zA-Z0-9]/g,'_'), e)}
className="icon" type="caret-right" />,
<Popconfirm placement="topRight" title="Are you sure delete this image?"
onConfirm={(e) => this.actionClick('REMOVE_IMAGE',image.Id, e)} okText="Yes" cancelText="No">
<Icon key="4" className="icon" type="close" />
</Popconfirm>
]
}>
<List.Item.Meta
title={image.RepoTags[0]}
description={image.Labels ? image.Labels.maintainer : ''}
</List.Item.Meta>
<InputGroup compact className={'inputGroup'}>
<Input style={{ width: '50%' }} placeholder={'inner port'} value={this.state.innerPort} onChange={evt => this.updateValue("innerPort",evt)}/>
<Input style={{ width: '50%' }} placeholder={'redirect'} value={this.state.redirectPort} onChange={evt => this.updateValue("redirectPort",evt)}/>
</InputGroup>
</List.Item>
)}
>
</List>
);
}
As you can see in the code I have an InputGroup for every List.Item and I store the value in the state using:
updateValue(k,v) {
console.log("key", k, "value", v);
console.log(this.state);
this.setState({
[k]:v.target.value
});
}
The problem here is that the I have the same value for every List.Item of the List.
How could I manage this problem with multiple List.Item? I thought of an array, but I didn't make that work.

Change your Input to
<Input style={{ width: '50%' }} placeholder={'inner port'} value={this.state["innerPort"+image.id] } onChange={evt => this.updateValue("innerPort",image.Id,evt)}/>
this will send a unique identifier to the update function and then you can use it like
updateValue(k,id,v) {
console.log("key", k, "value", v);
console.log(this.state);
var myKey=k+id
this.setState({
[myKey]:v.target.value
});
}

Have you tried to use FlatList instead of List, so you can pass the item index to the rendered item.

Related

v4 material ui autocomplete is not resting value?

I have the following advanced autocomplete logic in the past I used key to re render the whole component after submitting a form that is located else where any idea how to rest it the proper way ? my problem is I need to find a way to connect a value in to it a value that is connected to state some how and when my form will submit and the value will rest, (rest value will be triggered during submitting) so the autocomplete value will rest as well any idea how to integrate value using state in to this logic ?
const options = [{name : 'some option' , optionType : 'some type', tool : 'some tool'}, ...]
<Autocomplete
id='advancedselect'
ref={refAutocomplete}
options={options.sort((a, b) => -b.optionType.localeCompare(a.optionType))}
groupBy={(option: any) => option.optionType}
getOptionLabel={(option) => option.name}
renderOption={(option) => (
<React.Fragment>
<div style={{ width: '12vw', maxWidth: 75, marginRight: 10, padding: 0 }}>
<IconsOption img={option.tool} />
</div>
{option.name}
</React.Fragment>
)}
//value={val}
//onChange={(event) => setVal(event.currentTarget)}
//getOptionSelected={(option, value) => option.name === value.name}
PaperComponent={({ children }) => <Paper className={classes.backDrop}>{children}</Paper>}
PopperComponent={(props: any) => <Popper open={open.open} anchorEl={open.anchorEl} {...props} className={classes.popper} placement='bottom'></Popper>}
onClose={() => setOpen({ /*anchorEl: null,*/ ...open, open: false })}
onOpen={(event: any) => {
const { currentTarget } = event;
setOpen({
anchorEl: currentTarget,
open: true,
});
}}
onInputChange={handleAutoComplete}
className={classes.root}
renderInput={(params) => (
<TextField
name='field'
error={err.exercise ? true : false}
onChange={handleTextField}
{...params}
InputLabelProps={{ shrink: false }}
label={!text.length && !selected.stateOptions? `Selectd Opitons !!` : ' '}
onBlur={restTextOnBlurCond}
autoComplete='off'
/>
)}
/>

How to get multiple checkbox values on submit reactjs

I have a multiple recepient email and multiple checkbox column
I want to get each recepient email and checkbox values on submit.I am getting recepient emails on submit but no checkbox values. Kindly help
The form looks like this.
Here is my code
export default function ShareReportView(props) {
const [recipientEmails, updateRecicpientEmails] = useState({});
const handleInputChange = (e, name) => {
updateRecicpientEmails((prevState) => ({
...prevState,
[name]: e.target.value,
}));
};
const extratEmailList = (emailsList) => {
if (!emailsList || !Object.keys(emailsList).length) {
return;
}
console.log('obj email list',Object.values(emailsList))
return Object.values(emailsList);
};
const handlepermission = () => {
};
function sendEmail(recipientEmailsList) {
const rEmails = extratEmailList(recipientEmailsList);
console.log(rEmails);#prints all emails here
#here i want to get all checkbox values here on submit
}
return (
<div className="container">
{[...Array(count)].map((val, index) => (
<div key={index} className={`${styles["textField"]}`}>
<div style={{ float: "left" }}>
<Box
component="form"
sx={{
"& > :not(style)": { marginRight: 4, width: "31ch" },
}}
noValidate
autoComplete="off"
>
{" "}
<FormControl variant="standard">
<InputLabel
htmlFor="component-simple">
Recipient E mail
</InputLabel>
<Input
id="component-simple"
onChange={(event) =>
handleInputChange(
event,
`recipient_email_${index++}`,
false
)
}
name={`recipient_email_${index++}`}
key={`recipient_email_${index++}`}
disableUnderline={true}
/>
</FormControl>
<FormControlLabel
control={
<Checkbox
color="default"
onClick={() => {
handlepermission(`${index++}`);
}}
/>
}
label="Allow user to perfrom action"
name={`allow_user_edit_${index++}`}
/>
</Box>
</div>
</div>
))}
<div className="btn">
<button
className={`${styles.send}`}
onClick={() => sendEmail(recipientEmails)}
>
SEND
</button>
</div>
</div>
)}
I am not on my computer but following should work
export default function ShareReportView(props) {
const [recipientEmails, updateRecicpientEmails] = useState([]);
const handleEmailChange = (e, index) => {
let temp = [...recipientEmails]
let tempObj = {...temp[index]}
tempObj.email = e.target.value
temp.splice(index, 1, tempObj)
updateRecicpientEmails(temp)
};
const handlePermissionChange = (e, index) => {
let temp = [...recipientEmails]
let tempObj = {...temp[index]}
tempObj.permission = e.target.value
temp.splice(index, 1, tempObj)
updateRecicpientEmails(temp)
};
function sendEmail(recipientEmailsList) {
recipientEmails.forEach(e => {
console.log(e.email, e.permission)
})
}
return (
<div className="container">
{[...Array(count)].map((val, index) => (
<div key={index} className={`${styles["textField"]}`}>
<div style={{ float: "left" }}>
<Box
component="form"
sx={{
"& > :not(style)": { marginRight: 4, width: "31ch" },
}}
noValidate
autoComplete="off"
>
{" "}
<FormControl variant="standard">
<InputLabel
htmlFor="component-simple">
Recipient E mail
</InputLabel>
<Input
id="component-simple"
onChange={(event) =>
handleEmailChange(
event,
index
)
}
name={`recipient_email_${index++}`}
key={`recipient_email_${index++}`}
disableUnderline={true}
/>
</FormControl>
<FormControlLabel
control={
<Checkbox
color="default"
onClick={(e) => {
handlePermissionChange(e, index);
}}
/>
}
label="Allow user to perfrom action"
name={`allow_user_edit_${index++}`}
/>
</Box>
</div>
</div>
))}
<div className="btn">
<button
className={`${styles.send}`}
onClick={() => sendEmail(recipientEmails)}
>
SEND
</button>
</div>
</div>
)}
Let me know if you feel any issues, will be happy to help you, you should also change the logic of add and remove entries button. On add button just add a new object with empty values in recipientEmails list. and use your map function in render on recipientEmails.
Edit # 1
function addNewEntry(){ //call this on add new entry button
let temp = [...recipientEmails]
temp.push({
email: '',
permission: false
})
updateRecicpientEmails(temp)
}
you can use addNewEntry for adding new row. but now your will have to edit your render function something like this
replace {[...Array(count)].map((val, index) => (
with {recipientEmails.map((val, index) => (
in your return staement
You need to save multiple values on the same object per recipient, I did this change on your handleInputChange function, now it creates an object per recipient
const handleInputChange = (e, name) => {
updateRecicpientEmails((prevState) => ({
...prevState,
[name]: {
email: e.target.value
}
}));
};
and I call it like this
handleInputChange(event, `recipient_${index}`, false)
removed _email from there.
And for the handle permission, just add a new property to the recipient object with the checkbox value
const handlepermission = (index, value) => {
updateRecicpientEmails((currentRecipients) => ({
...currentRecipients,
[index]: {
...currentRecipients[index],
allow: value
}
}));
};
this function runs on input change, so just add this to prop to the input:
onChange={({ target: { checked } }) => {
handlepermission(`recipient_${index}`, checked);
}}
To be honest is easier if you use the native form submit handler and FormData API, here is an example:
https://codesandbox.io/s/formdata-api-example-xkvi8

google react-places-autocomplete api restrict search suggestions to Australia / single country

Hello I want to limit my search suggestions (and therefore limit a user to choose an Australian address) with react places autocomplete to addresses from Australia, and to note I have checked stack overflow for similar questions and none of them seem to work, here is an example of the suggestions I am currently getting that i would like to be only Australian Suggestions.
screen shot
here is what i think is the relevant code
import PlacesAutocomplete, {
geocodeByAddress,
getLatLng,
} from 'react-places-autocomplete';
<PlacesAutocomplete
fullWidth
className="search-bar"
value={address}
onChange={setAddress}
onSelect={handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div >
<input
style={{width:"100%" }}
{...getInputProps({
placeholder: 'Enter Job Address',
className: 'location-search-input',
})}
/>
<div className="autocomplete-dropdown-container"
key={suggestions.description}
>
{loading && <div>Loading...</div>}
{suggestions.map((suggestion, index)=> {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
key={index}
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description }</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
try with this prop
searchOptions={{componentRestrictions: { country: ['au'] }}}

React Final Form with react-places-autocomplete

I've looked at a bunch of other similar questions, but none are answered!
So far I have created a standard record-level which looks like this: https://final-form.org/docs/react-final-form/examples/record-level-validation
I am using React Final Form with react-places-autocomplete. I want to include the selections of react-places-autocomplete to show in the values as seen in the link above, when you enter information into the fields.
I have tried to add the following code based on react-places-autocomplete:
<Field name="location">
{({input, meta}) => (
<PlacesAutocomplete
value={address}
onChange={setAddress}
onSelect={handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<p> latitude: {coordinates.lat}</p>
<p> longitude: {coordinates.lng}</p>
<input
{...input}
{...getInputProps({
placeholder: 'Search Places ...',
className: 'location-search-input',
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
)}
</Field>
I'm wondering how I add the input of the placeautocomplete into this value here:
<pre>{JSON.stringify(values, undefined, 2)}</pre>
Sorry my answer is old, but try using react-google-places-autocomplete. Much better here is how you can use it....
<Field name="city">
{({ input, meta }) => (
<div style={{ width: '100%' }}>
<GooglePlacesAutocomplete
selectProps={{
value: input.value,
onChange: e => {
input.onChange(e.label)
},
}}
apiKey={GOOGLE_API_KEY}
autocompletionRequest={{
componentRestrictions: {
// country: [values.group_country && values.group_country.value]
country: ['CA', 'GB', 'US']
},
types:['(cities)']
}}
/>
{meta.error && meta.touched &&
<span className="text-danger small block">{meta.error}</span>}
</div>
)}
</Field>
The answer is really help but I found the input field was empty after I selected the address so I removed one line "value: input.value," it works for me.

Ant design <Form.List> create static array of forms

I am using antd with react to develop an application.
<Form.List name="secondaryContacts">
{(fields, { add, remove }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item
{...formItemLayoutWithOutLabel}
label={index === 0 ? "" : ""}
required={false}
key={field.key}
>
<Form.Item
{...field}
validateTrigger={["onChange", "onBlur"]}
rules={[
{
required: true,
validator: phoneNumberValidator
}
]}
>
<Input
placeholder="Secondary Contact"
addonAfter={
fields.length >= 1 ? (
<MinusCircleOutlined
onClick={() => {
remove(field.name);
}}
/>
) : null
}
/>
</Form.Item>
</Form.Item>
))}
<Form.Item {...formItemLayoutWithOutLabel}>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
<PlusOutlined /> Add Secondary Contact
</Button>
</Form.Item>
</div>
);
}}
</Form.List>;
Above is the code I am using to add dynamic form fields with validation using Form.List.
Now I have a specific scenario where I need to show 7 Sliders(https://ant.design/components/slider/) for the selected time slot and store them in an array, so I thought of using Form.List and keep all sliders inside just like above(except that it's static).
But I am not clear how I can achieve it with Form.List and there are very few examples on the internet.
I have a scenario where I need to have an array of forms and club them as an array using Form.List.
You can use the initialValue property to set the static data
Example:
const staticValue = [{ formItem1: 'value1', formItem2: 'value2'}];
<Form.List name="formListName" initialValue={staticValue}>
{(fields, { add, remove }, { errors }) => (
fields.map((field) => (
<>
<Form.Item {...field} name={[field.name, 'formItem1']}>
<Input placeholder="Field 1" />
</Form.Item>
...
You still need <Form> component
Try
<Form>
<Form.List>
</Form.List>
</Form>

Resources