update1: updated image for better understanding
I am trying to implement chip filters similar to googleflights. Right now when you select sports it will show sports1 it will replace sports by sports1.
However, I wanted to insert a textbox, when I enter somevalue in the textbox and hit Enter the primary fee schedule value should change to the entered value.
Can you tell me how to fix it?
chip related code is in chip-selector and tab-demo
since if I enter textbox tag. I am just getting string
code snippet and sandbox
const primaryFeeMenuItems = [
"primaryFeeMenuItems1",
"<input type=\"text\" name=\"fname\">",
"primaryFeeMenuItems2",
"primaryFeeMenuItems3"
];
<td>
<SimpleMenu
buttonName="Primary Fee Schedule"
menuItems={primaryFeeMenuItems}
/>
</td>
handleDelete() {
this.setState({ display: !this.state.display });
}
handleClick = event => {
console.log("handle Click");
this.setState({ anchorEl: event.currentTarget });
};
handleClose = e => {
console.log(e.menuItem);
if (e.menuItem) {
this.setState({ display: !this.state.display });
this.setState({ chipName: e.menuItem });
}
this.setState({ anchorEl: null });
};
You are using Menu which works a little differently than what you are trying to achieve. Actually looking into how Google Flights is using these filters, it seems like they are using Chips and Dialog components to produce that result. Once you use a Dialog component, you can define the content yourself.
I have created a sandbox here
I converted your code to take Dialog instead of Menu.
<div>
<Chip
style={{ display: this.state.display ? "" : "none" }}
label={this.state.chipName}
onDelete={this.handleDelete}
className={this.props.classes.chip}
color="primary"
/>
<Button
style={{ display: this.state.display ? "none" : "" }}
aria-owns={anchorEl ? "simple-menu" : undefined}
aria-haspopup="true"
onClick={this.handleClick}
>
{this.props.buttonName}
</Button>
<Dialog
onClose={this.handleClose}
aria-labelledby="simple-dialog-title"
open={this.state.openDialog}
>
<DialogTitle id="simple-dialog-title" style={titleStyle}>
Set backup account
</DialogTitle>
<div>
<input type="text" placeHolder="type here" />
<List>{menuItems}</List>
</div>
</Dialog>
</div>
menuItems returns ListItem instead of MenuItems. Find the full code in the sandbox.
The input you are trying to get should be before the List. You can handle that any way you want.
I haven't overridden the CSS properties for Dialog. So, once you override the backdrop background color and position of the dialog, you should achieve the display as well.
Related
I have a form in my react application which is inside a modal pop up. so when the user closes the pop up i want to check if there is any changes made in the form fields.If so i will show a confirmation modal and if no changes i will close the pop up.
<FormProvider {...methods}>
<form onSubmit={handleSubmit(submitDetails)}>
<FormInput
onChange={handleChange(onChange, value)}
onBlur={onBlur}
value={value ?? ""}
name="name"
/>
<FormInput
onChange={handleChange(onChange, value)}
onBlur={onBlur}
value={value ?? ""}
name="age"
/>
<section className="submit-section">
<Button onClick={() => checkUnsavedAndClose()}>Cancel</Button>
<Button type="submit" disabled={!isValid}>
Save
</Button>
</section>
</form>
</FormProvider>
const checkUnsavedAndClose = () => {
// if the form is not updated
closePopUp();
// if the form is updated
alertPopup();
}
What is the best approach to validate the entire form irrespective of number of fields in it. i was thinking of checking whether the form is touched or dirty. but i am not sure that it would be the best solution. any inputs will be highly appreciated
Assuming the "handleChange" function is used for all inputs one thing you could do is use it to hold on state a variable for changes
handleChange(onChange, value) {
value !== originalValue && setState({anyChanges: true}) //or useState and set the state inside the modal
onChange(value)
}
you could also hold which fields were modified and not save to improve the pop-up message
by creating a boolean changed state. that you can change true/false. And you check the value when you try to close the popup.
const [changed, setChanged] = useState(false);
const handleChange() {
// your code
setChanged(true)
}
const checkUnsavedAndClose = () => {
if(changed) {
alertPopup();
} else {
closePopUp();
setChanged(false)
}
I am currently working on an update form (put request) on ReactJS. I have the form data stored as this.state that I want to use to prepopulate, however, I am not sure how to implement it into the dynamic field, as I would want the prepopulated data to still hold on to the 'remove' function to remove that row of fields from the form. Also, I would want the rows to be rendered automatically when the form is rendered. Meaning, if there are two rows of the dynamic field, those two rows has to be shown without pressing the 'add' button. Below is the snippet of the code and a screenshot of the form.
<Form.List name={addon.model} key={addon.model}>
{(fields, { add, remove }) => {
return (
<div>
{fields.map((field, index) => (
<Row key={field.key}>
{addon.fields.map((a) => (
<Col key={'c' + a.key}>
<Input placeholder={a.label} name={a.key} key={'i' + a.key}
onChange={(e) => this.onChangeAddOn(e, index, addon.model)} />
</Col>
))}
<Col flex="none">
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => {
remove(field.name);
}}
/>
</Col>
</Row>
))
}
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
<PlusOutlined /> Add POCs
</Button>
</div>
);
}}
</Form.List>
screenshot (the '-' button is the remove button, and i am free to add more fields if i press the 'Add POC' button, but the main point is that the two rows of data must be rendered at the start together with the form => data stored in this.state)
All help is appreciated and welcomed, please do help to point me in the right direction as I am still new to ReactJS! I did take a look at render props and Form.List, but I am not sure how to implement it still.
I'm having an input validation problem thats allowing the form to submit without having any selectorValues added. The check I have seems to only check for input inside the textarea but doesn't account for the Add button being pressed.
Here's a sandbox reproducing the issue.
I'm using Semantic-ui-react so my <Form.Field /> looks like this:
<Form.Field required>
<label>Selector Values:</label>
<TextArea
type="text"
placeholder="Enter selector values 1-by-1 or as a comma seperated list."
value={this.state.selectorValue}
onChange={this.handleSelectorValueChange}
required={!this.state.selectorValues.length}
/>
<Button positive fluid onClick={this.addSelectorValue}>
Add
</Button>
<ul>
{this.state.selectorValues.map((value, index) => {
return (
<Card>
<Card.Content>
{value}
<Button
size="mini"
compact
floated="right"
basic
color="red"
onClick={this.removeSelectorValue.bind(this, index)}
>
X
</Button>
</Card.Content>
</Card>
);
})}
</ul>
</Form.Field>
So in the above, <TextArea> has a required prop: !this.state.selectorValues.length. This is only checking for input inside the textarea, it should check that the value has been added by pressing the Add button before allowing the form to submit.
In your addSelectorValue add a check to see if this.state.selectorValue it not empty, if it is just return, this will prevent adding empty values to selectorValues
addSelectorValue = e => {
e.stopPropagation();
e.preventDefault();
if (!this.state.selectorValue) return;
//continue if this.state.selectorValue has a value
};
Before submitting add a check to see if this.selectorValues is empty, if so focus on textarea.
To focus we need to first create a ref to our textarea.
Create a ref to be
attached to a dom element
textareaRef = React.createRef();
// will use our ref to focus the element
focusTextarea = () => {
this.textareaRef.current.focus();
}
handleSubmit = () => {
const { selectorValues } = this.state;
if (!selectorValues.length) {
// call our focusTextarea function when selectorValues is empty
this.focusTextarea();
return;
}
this.setState({ submittedSelectorValues: selectorValues });
};
// attach our ref to Textarea
<Textarea ref={this.textareaRef} />
After some search ... required prop is for decorational purposes only - adding astrisk to field label.
It has nothing to form validation. You need a separate solution for that - try formik or set some condition within submit handler.
Formik plays nicely with yup validation schema - suitable for more complex, dynamic requirements.
I am displaying cards with data mapped with a price and location
return data.map( FD1 => (
<Row>
<Card className="card">
<Card body className="text-center">
<CardTitle data-es-label="location"> Location:
{FD1.Departure}
</CardTitle>
<CardText data-es-label="Price">Price
{FD1.price}
</CardText>
<label>
<Checkbox
id={FD1.FlightID}
name={FD1.FlightID}
checked={this.state.checked === FD1.FlightID}
onChange={this.handleCheckboxChange}/>
<span>Select</span>
</label>
<CardActions>'
Each card has a check box and my idea was when the check box is selected and submitted - the information mapped to that card will be sent to be 'booked'.
Is it possible to filter data from the mapped data. Each 'card' with the data has a unique id. How do I filter the data by card and send to a booking page with the details?
At the moment when I select a checked box they all select.
handleCheckboxChange = event =>
this.setState({ checked: event.target.checked });
EDIT: attempt - this is what I have tried
handleCheckboxChange = event =>
this.setState({ checked: event.target.checked });
Select(FD) {
this.state={checked:FD.FlightID};
return(
<label>
<Checkbox id={FD.FlightID}
name={FD.FlightID}
checked={this.state.checked}
onChange={this.handleCheckboxChange}
/>
<span>Select</span>
</label>
)
}
Do you know where I have gone wrong?
into the checked state save the FD1.FlightID instead of true/false and you will know exactly which card had been checked.
and then on submit you can send the appropriate data using this.state.checked (the id of checked card)
In the code inside your "map" function, "this" is still referring to the parent component. So you only have one checked state. That's why all your checkboxes show the same behaviour.
A cleaner solution would be to define a new stateful component "CardRow" that has everything inside the map plus it's own state and handleCheckboxChange function.
Alrighty, so I'm using some color picker that changes my this.state.colorPicked and that works fine, now I have an input field I'd like to write a function that I can call that would concat the value of my state colorPicked if it was empty, or concat comma and that value if it was not, how can I access this input field?
I'm using react-bootstrap
<InputGroup className="mb-3">
<FormControl
name="color"
onChange={this.change}
placeholder="Available Colors"
aria-label="Available Colors"
/>
</InputGroup>
<div style={{ display: "flex", "flex-direction": "row" }}>
<TwitterPicker
className="mb-3"
onChange={this.handleColorChange}
/>
<Button
style={{
background: this.state.colorPicked
}}
onClick={() => this.addColor(this.state.colorPicked)}
>
Add Color!
</Button>
</div>
TIA
Clarification: I want to pick the color, the onchange detector sets it to the state and hence the button's background, now on button click I want to add it's hex (the state) to the text field as text input, if input is not empty I would precede that with a comma.
With react forms we use 2 way binding from state, onChange and value attributes.
First add the value attribute and set it to state property for ex inputField.
<FormControl
name="color"
onChange={this.change}
placeholder="Available Colors"
aria-label="Available Colors"
value=={this.state.inputField}
/>
Now you can write a logic inside your change function.. something like
change = (e)=>{
this.setState({inputField:e.target.value}
// then copy array from state
let arrFromState = [...this.state.colorPicked]
let updatedArray = [...arrFromState, this.state.inputField]
// or use concat, push etc
this.setState({colorPicked:updatedArray})
}
I didn't understood the exact thing you wanted to do.
But thats the basic approach while working with react forms. Two way binding
To access input value you can use onChange method on your input, pass it an event and access it through event.target.value. It should look similar to this:
<input onChange={(event) => logInputValue(event)}
const logInputValue = ({ event: { target: { value } = {} } }) => { console.log(value) }