How to generate a component in React Form onClick - javascript

I am struggling with some React functionality. My goal is to create a form where a day template can be added (for context - like a training club can make up a template of trainings for the day and then schedule them regularly). For that I wanted to add a button which onClick will create a smaller block with 2 form fields - time and training info. And I need user to add several of those, as much as they want.
The thing is, while I understand a bit how react works, it seems to me I am just banging my head against the wall with this, as one thing is to render a component, but another to generate a bunch of same, completely new ones and connected to the form somehow, so I can send the data when clicking submit button.
Here is repository with this component:
https://github.com/badgerwannabe/spacefitness-test-client
Here is path to this component
spacefitness-test-client/src/components/template-components/addTemplateForm.js
Here below how it looks rendered
UPDATE 1 here is the full component here:
import React, {useState} from "react";
import {useMutation } from "#apollo/client";
import {useForm} from '../../utils/hooks'
import { Button, Form } from "semantic-ui-react";
import {FETCH_TEMPLATES_QUERY, FETCH_TRAININGS_QUERY,ADD_TEMPLATES_MUTATION} from '../../utils/graphql'
//hook for form functioning
function AddTemplateForm (props){
const {values, onChange, onSubmit} = useForm(createDayCallback,{
date:'', dayTrainings:[{
time:'testing time', training:"60e9e7580a6b113b2486113a"
},{
time:'testing2 time2', training:"61ec6a6d0f94870016f419bd"
}
]
});
//apollo hook to send data through GraphQL
const [createDay, {error}] = useMutation(ADD_TEMPLATES_MUTATION, {
errorPolicy: 'all',
variables:values,
update(proxy, result){
const data = proxy.readQuery({
query:FETCH_TEMPLATES_QUERY,
});
proxy.writeQuery({query:FETCH_TEMPLATES_QUERY,
data:{
getDays: [result.data.createDay, ...data.getDays]
}})
props.history.push('/templates')
},},
{});
function createDayCallback(){
createDay();
}
//little component I want to dynamically add each time people press a button
function addDayTraining(){
const addDayTraining = (
<>
<Form.Field>
<Form.Input
placeholder="time"
name="time"
onChange={()=>{
console.log("time")
}}
values={values.time}
error={error ? true : false}
/>
<Form.Input
placeholder="training"
name="training"
onChange={()=>{
console.log("training")
}}
values={values.training}
error={error ? true : false}
/>
</Form.Field>
</>
)
return addDayTraining
}
//Form component itself
const AddTemplateForm = (
<>
<Form onSubmit={onSubmit}>
<h2>Add a template :</h2>
<Form.Field>
<Form.Input
placeholder="date"
name="date"
onChange={onChange}
values={values.date}
error={error ? true : false}
/>
</Form.Field>
<Form.Field>
<Button type="button" onClick={
addDayTraining
}>Add training</Button>
</Form.Field>
<Button type ="submit" color="teal">Submit</Button>
</Form>
{error && (
<div className="ui error message" style={{marginBottom:20}}>
<li>{error.graphQLErrors[0].message}</li>
</div>
)}
</>
)
return AddTemplateForm
}
export default AddTemplateForm;

Can you just set up a function on the submit button which pushes an object with {time: new Date(), trainingInfo: ""} and push that object into an existing array of training objects? (obviously starting empty)
You could then map those objects into a component and when the component is updated (i.e. when the user adds a time and training details text) use a callback function to update the values in the array at the index of that object.
export default function yourIndexPage({yourprops}) {
const [trainingObjects, setTrainingObjects] = useState([]);
function addTraining(){
const newTrainingObject = {
time: new Date(), //assuming you want it to default to todays date
trainingInfo: "your placeholder text"
};
setTrainingObjects([...trainingObjects, newTrainingObject]);
}
//I am assuming your training object will be a list item here so wrapped in <ul>
return(
<div>
<div className='your list of training things'> (might need to set style as flex and add some padding etc..)
{trainingObjects.length === 0 ? <div/> : trainingObjects.map((trainingObject, index) => (
<YourTrainingObjectComponent trainingObject={trainingObject} trainingItemIndex={index} key={index}/>
))}
</div>
<Button onClick={() => {addTraining}} />
</div>
)
}

Related

With React, what is the best way to pass a useState array back and forth between components?

I had some help with a previous issue with my little project, but I have a new problem I can't seem to understand. My program takes an array of objects (call them cards), and displays an on-screen card for each element in the array. I have an edit button for each card, which should open the edit form for the chosen item, and pre-populate it with its current state - this all works.
I want to be able to edit the item, save it back in place into the array, and have that 'card' updated. This is the main component:
import React from "react";
import ReactFitText from "react-fittext";
import Editform from "./Editform";
function Displaycards({ lastid }) {
// dummy data hardcoded for now
const [cards, setCards] = React.useState([
{
id: 1,
gamename: "El Dorado",
maxplayers: 4,
freespaces: 1,
tablenum: 5,
},
{
id: 2,
gamename: "Ticket to Ride",
maxplayers: 4,
freespaces: 2,
tablenum: 3,
},
]);
const [showForm, setShowForm] = React.useState(false);
const [currentid, setCurrentid] = React.useState(0);
return (
<div className="cardwrapper">
{cards.map(({ id, gamename, maxplayers, freespaces, tablenum }) => {
return (
<div key={id}>
<div>
<div className="card">
<ReactFitText compressor={0.8}>
<div className="gamename">{gamename}</div>
</ReactFitText>
<div className="details">
<p>Setup for: </p>
<p className="bignumbers">{maxplayers}</p>
</div>
<div className="details">
<p>Spaces free:</p>
<p className="bignumbers">{freespaces}</p>
</div>
<div className="details">
<p>Table #</p>
<p className="bignumbers">{tablenum}</p>
</div>
<button type="button" className="playbutton">
I want to play
</button>
<br />
</div>
<div className="editbuttons">
<button
type="button"
className="editbutton"
onClick={() => {
setShowForm(!showForm);
setCurrentid(id);
}}
>
Edit
</button>
<button type="button" className="delbutton">
X
</button>
</div>
</div>
</div>
);
})}
{showForm && (
<div>
<Editform cards={cards} setCards={setCards} id={currentid} />
</div>
)}
</div>
);
}
export default Displaycards;
and this is the Editform.js which it calls at the bottom. As far as I can tell I'm passing my array, setter function, and id of the card I want to edit:
function Editform({ cards, setCards, id }) {
const thisCard = cards.filter((card) => card.id === id)[0];
const editThisCard = thisCard.id === id; // trying to match id of passed card to correct card in 'cards' array.
console.log(editThisCard);
function saveChanges(cardtochange) {
setCards(
cards.map(
(
card // intention is map back over the original array, and if the id matches that
) =>
card.id === id // of the edited card, write the changed card back in at its ID
? {
id: id,
gamename: cardtochange.gamename,
maxplayers: cardtochange.maxplayers,
freespaces: cardtochange.freespaces,
tablenum: cardtochange.tablenum,
}
: card // ... or just write the original back in place.
)
);
}
return (
<>
{editThisCard && ( // should only render if editThisCard is true.
<div className="form">
<p>Name of game:</p>
<input type="text" value={thisCard.gamename}></input>
<p>Max players: </p>
<input type="text" value={thisCard.maxplayers}></input>
<p>Free spaces: </p>
<input type="text" value={thisCard.freespaces}></input>
<p>Table #: </p>
<input type="text" value={thisCard.tablenum}></input>
<p></p>
<button
type="button"
className="playbutton"
onClick={saveChanges(thisCard)} //remove to see edit form - leave in for perpetual loop.
>
Save changes
</button>
</div>
)}
</>
);
}
export default Editform;
If I comment out the onClick for the button, the page renders. If it's in there, the page gets stuck in an infinite loop that even React doesn't catch.
The way I'm trying to recreate my array is based on advice I've read here, when searching, which said to take the original array, rebuild it item-for-item unless the ID matched the one I want to change, and to then write the new version in.
I suspect there might be a way to do it with my setter function (setCards), and I know there's an onChange available in React, but I don't know a) how to get it to work, or b) how - or even if I need to - pass the changed array back to the calling component.
Your function is invoked directly upon components render:
{saveChanges(thisCard)}
Rename it to a callback style signature:
{() => saveChanges(thisCard)}
Also do add a jsfiddle/ runnable snippet for answerers to test ✌️.
Edit:
About the array of objects passing and updates, at your part the code is good where filter is used. We can apply idea of moving update logic to parent where data is located.
Now id + updated attributes could be passed to the update callback in child.
To give you hint, can use spread operator syntax to update items out of existing objects.

How to implement a check all button for radio buttons, using React Hooks?

Don't get this confused with checking each radio button I have on the page. I want to implement a check all button that sets the value of a nested object state equal to a certain value. I am storing each question in a nested state. Ex.
formQuestions({
kitchen: [question,question2,question3],
living: [question,question2,question3]
})
Four radio buttons are being made for each question. Now one radio button can only be selected at once. Each radio button has its' own value. Ex. `"Good", "Fair", "Poor", "N/A".
When a radio button is selected a state is generated dynamically for that section and question. Ex.
formAnswers({
kitchen: {
question: "Good"
question2: "Poor"
}
})
The goal here is the button that I want to create that checks only one value for each question Ex. clicks button question: "Good", question2: "Good" etc..
For me to set the state of a dynamic value I would need the "Section name" lets call it Name and the "Question" we'll call it question. That would give me access to the value like so formAnswers[Name][question]: value
I am trying to set that state from a component called SectionHeader. These contain the buttons.
SectionHeader.js
import { FormAnswersContext, FormQuestionsContext } from "../../Store";
function SectionHeader({ title, name }) {
const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);
return (
<div>
<h1 className={styles["Header"]}>{title}</h1>
<div className={styles["MarkAllWrapper"]}>
<button className={styles["MarkAll"]}>
Mark all items as "Good" in this section
</button>
<br />
<button className={styles["MarkAll"]}>
Mark all items as "N/A" in this section
</button>
</div>
</div>
);
}
The parent of Section Header and the rest of the form code excluding the child radio buttons which I have explained, are in another component LivingRoom.js
LivingRoom.js
import { FormQuestionsContext, FormAnswersContext } from "../../Store";
function LivingRoomForm({ Name }) {
const [expanded, setExpanded] = useState(false);
const [formQuestions, setFormQuestions] = useContext(FormQuestionsContext);
const [formAnswers, setFormAnswers] = useContext(FormAnswersContext);
const array = formQuestions.living;
const onChange = (e, name) => {
const { value } = e.target;
setFormAnswers((state) => ({
...state,
[Name]: { ...state[Name], [name]: value },
}));
};
const handleOpen = () => {
setExpanded(!expanded);
};
return (
<div>
<Button
className={styles["CollapseBtn"]}
onClick={handleOpen}
style={{ marginBottom: "1rem", width: "100%" }}
>
<p>LIVING ROOM INSPECTION</p>
<FontAwesome
className="super-crazy-colors"
name="angle-up"
rotate={expanded ? null : 180}
size="lg"
style={{
marginTop: "5px",
textShadow: "0 1px 0 rgba(0, 0, 0, 0.1)",
}}
/>
</Button>
<Collapse className={styles["Collapse"]} isOpen={expanded}>
<Card>
<CardBody>
{array ? (
<div>
<SectionHeader title="Living Room Inspection" name={Name} />
<div
className={styles["LivingRoomFormWrapper"]}
id="living-room-form"
>
{array.map((question, index) => {
const selected =
formAnswers[Name] && formAnswers[Name][question]
? formAnswers[Name][question]
: "";
return (
<div className={styles["CheckboxWrapper"]} key={index}>
<h5>{question}</h5>
<Ratings
section={Name}
question={question}
onChange={onChange}
selected={selected}
/>
</div>
);
})}
</div>
<br />
<ImageUploader name="living" title={"Living Room"} />
</div>
) : (
<div></div>
)}
</CardBody>
</Card>
</Collapse>
</div>
);
}
If there is anything I am missing please let me know, I would be happy to share it. Cheers
Edit: for anyone that needs the radio buttons component.
Ratings.js
import React from "react";
import { FormGroup, CustomInput } from "reactstrap";
function Ratings({ selected, section, question, onChange }) {
return (
<div>
<FormGroup>
<div>
<CustomInput
checked={selected === "Good"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Good`}
value="Good"
label="Good"
/>
<CustomInput
checked={selected === "Fair"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Fair`}
value="Fair"
label="Fair"
/>
<CustomInput
checked={selected === "Poor"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_Poor`}
value="Poor"
label="Poor"
/>
<CustomInput
checked={selected === "N/A"}
onChange={(e) => onChange(e, question)}
type="radio"
id={`${section}_${question}_NA`}
value="N/A"
label="N/A"
/>
</div>
</FormGroup>
</div>
);
}
I do not completely understand your question, I am sorry but I think this will help you.
Here is an implementation of radio buttons using react -
class App extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
handleChange = e => {
const { name, value } = e.target;
this.setState({
[name]: value
});
};
render() {
return (
<div className="radio-buttons">
Windows
<input
id="windows"
value="windows"
name="platform"
type="radio"
onChange={this.handleChange}
/>
Mac
<input
id="mac"
value="mac"
name="platform"
type="radio"
onChange={this.handleChange}
/>
Linux
<input
id="linux"
value="linux"
name="platform"
type="radio"
onChange={this.handleChange}
/>
</div>
);
}
}
After a few attempts, I was able to figure out the solution to this issue.
The key here was to figure out a way to get gather each question so that it may be used as a key when setting the state. As my questions were stored in a ContextAPI, I was able to pull them out like so...
this may not be the best solution however it worked for me.
const setStateGood = () => {
formQuestions[name].map((question) => {
setFormAnswers((state) => ({
...state,
[name]: { ...state[name], [question]: "Good" },
}));
});
};
const setStateNA = () => {
formQuestions[name].map((question) => {
setFormAnswers((state) => ({
...state,
[name]: { ...state[name], [question]: "N/A" },
}));
});
};
I was able to map through each question since the name is being passed through props is a key inside the actual object, formQuestions[name]. Because i'm mapping through each one I can set that question as a key and return the new state for each question to whatever I would like.
However, if I was to create an onClick={setState('Good')}, React didn't like that and it created an infinite loop. I will look for more solutions and update this post if I find one.

How to give validation in multi step form using react

I am working on a scenario where I have to do a multi-step form which I have already done, as well as the validation part. I am using react-hook-form for validation.
I have multi-step form:
in the first form I have several fields and one radio button
by default radio button is ticked on for auto generated pass so in this case I have nothing to do
the second one is let me create a password so in this case one input field will be show and the user will create the password
Issue
In my final form I am doing the validation like below:
{
fields: ["uname", "email", "password"], //to support multiple fields form
component: (register, errors, defaultValues) => (
<Form1
register={register}
errors={errors}
defaultValues={defaultValues}
/>
)
},
So to validate uname, email and password I am passing the values like above.
But when the radio button is ticked for auto generated password it is still handling the validation, I click on next and it is not going to next for because of password field.
And if I check the radio button as let me create the password it goes to next form and when I came back by clicking back it is going to auto generated password again and it is not holding the previous state. For other input fields it is handling the previous values but not in case of radio button scenario.
My full working code sandbox
Answer 1 The reason is you fields: ["uname", "email", "password"] is fixed, password is always to be taken validation.
Solution Need to store state of Form1 in App so you can check if the state of auto generated password is on remove password from the list
App.js
... other code
// need to move state and function form Form to app
const [show_input, setshow_input] = useState(false);
const createInput = () => {
setshow_input(true);
};
const auto_text = () => {
setshow_input(false);
};
const forms = [
{
// validate based on show_input state
fields: show_input ? ["uname", "email", "password"] : ["uname", "email"], //to support multiple fields form
component: (register, errors, defaultValues) => (
<Form1
register={register}
errors={errors}
defaultValues={defaultValues}
auto_text={auto_text}
createInput={createInput}
show_input={show_input}
/>
)
},
{
fields: ["lname"],
component: (register, errors, defaultValues) => (
<Form2
register={register}
errors={errors}
defaultValues={defaultValues}
/>
)
},
{
component: (register, errors, defaultValues) => (
<Form3
register={register}
errors={errors}
defaultValues={defaultValues}
/>
)
}
];
... other code
Answer 2 When you go next the Form1 is unmounted so its state is destroyed. When you store Form1's state in App.js you will fix this issue too
Bonus: It's prefered to use camalCase (E.g: showInput) rather than underscore (show_input)
The main problem is that you render the forms conditionally so all the previous form values are removed. The solution for this is to keep all forms mounted and just use display: none or display: block depending on which form is selected. This way all values will be persisted whenever you go to next or prev form or submit the form.
The second problem that you didn't remove the password field when it's unmounted so when moveToNext is called the valid argument in triggerValidation callback is always false. I fixed that by setting the fields for Form1 conditionally depending on if the password input is visible or not.
The third problem you are using defaultValues for the wrong purpose. You can get the current form values using getValues() which will return all the current values of the form.
I set the default value for uname field just as an example to show you how defaultValues should be used.
you can check the full solution here: https://codesandbox.io/s/fragrant-forest-75pzs?file=/src/App.js
here are all the changed files:
App.js
import React, { useState } from "react";
import Form1 from "./components/Form1";
import Form2 from "./components/Form2";
import Form3 from "./components/Form3";
import { useForm } from "react-hook-form";
function MainComponent() {
const {
register,
triggerValidation,
defaultValues,
errors,
getValues
} = useForm({
// You can set default values here
defaultValues: {
uname: "Lol"
}
});
console.log("Errors: ", errors);
const [currentForm, setCurrentForm] = useState(0);
// control password input visibility and Form1 fields
const [passwordVisible, setPasswordVisible] = useState(false);
const showPassword = () => {
setPasswordVisible(true);
};
const hidePassword = () => {
setPasswordVisible(false);
};
const forms = [
{
fields: passwordVisible
? ["uname", "email", "password"]
: ["uname", "email"],
component: (register, errors) => (
<Form1
// a key is needed to render a list
key={0}
// this will be used to set the css display property to block or none on each form
shouldDisplay={currentForm === 0}
register={register}
errors={errors}
showPassword={showPassword}
hidePassword={hidePassword}
passwordVisible={passwordVisible}
/>
)
},
{
fields: ["lname"],
component: (register, errors) => (
<Form2
key={1}
shouldDisplay={currentForm === 1}
register={register}
errors={errors}
/>
)
},
{
component: (register, errors) => (
<Form3
key={2}
shouldDisplay={currentForm === 2}
register={register}
errors={errors}
values={getValues()}
/>
)
}
];
const moveToPrevious = () => {
triggerValidation(forms[currentForm].fields).then(valid => {
if (valid) setCurrentForm(currentForm - 1);
});
};
const moveToNext = () => {
triggerValidation(forms[currentForm].fields).then(valid => {
if (valid) setCurrentForm(currentForm + 1);
});
};
const prevButton = currentForm !== 0;
const nextButton = currentForm !== forms.length - 1;
const handleSubmit = e => {
console.log("whole form data - ", getValues());
};
return (
<div>
<div className="progress">
<div>{currentForm}</div>
</div>
{forms.map(form => form.component(register, errors))}
{prevButton && (
<button
className="btn btn-primary"
type="button"
onClick={moveToPrevious}
>
back
</button>
)}
{nextButton && (
<button className="btn btn-primary" type="button" onClick={moveToNext}>
next
</button>
)}
{currentForm === 2 && (
<button
onClick={handleSubmit}
className="btn btn-primary"
type="submit"
>
Submit
</button>
)}
</div>
);
}
export default MainComponent;
Form1
import React from "react";
function Form1({
register,
errors,
shouldDisplay,
passwordVisible,
showPassword,
hidePassword
}) {
return (
<div style={{ display: shouldDisplay ? "block" : "none" }}>
<form autoComplete="on">
<br />
<div className="form-group">
<label>User name</label>
<input type="text" name="uname" ref={register({ required: true })} />
{errors.uname && <span>required</span>}
<label>Email</label>
<input type="email" name="email" ref={register({ required: true })} />
{errors.email && <span>required</span>}
</div>
<div>
<div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
<label className="form_label">Password</label>
<div className="form-check">
<label>
<input
type="radio"
name="auto_pass"
id="Radios1"
value="auto_pass"
className="form-check-input"
defaultChecked={true}
onChange={hidePassword}
/>
Auto generated password
</label>
</div>
<div className="form-check">
<label>
<input
type="radio"
name="auto_pass"
id="Radios2"
value="let_me"
className="form-check-input"
onChange={showPassword}
/>
Let me create the password
</label>
</div>
</div>
{passwordVisible && (
<div className="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12 mb-3">
<label className="form_label">Password</label>
<input
type="password"
name="password"
className="form-control"
ref={register({ required: true })}
/>
{errors.password && (
<span className="text-danger">Password is reguired</span>
)}
</div>
)}
</div>
</form>
</div>
);
}
export default Form1;
Form2
import React from "react";
function Form2({ register, errors, shouldDisplay }) {
return (
<div style={{ display: shouldDisplay ? "block" : "none" }}>
<form autoComplete="on">
<br />
<div className="form-group">
<label>User last name</label>
<input type="text" name="lname" ref={register({ required: true })} />
{errors.lname && <span>required</span>}
</div>
</form>
</div>
);
}
export default Form2;
Form3
import React from "react";
function Form3({ values, shouldDisplay }) {
return (
<div style={{ display: shouldDisplay ? "block" : "none" }}>
<h3>Want to display all values here like below</h3>
{Object.entries(values).map(([key, value]) => (
<p key={key}>
{key}: {value}
</p>
))}
<br />
<p>So that use can check for any Wrong info</p>
</div>
);
}
export default Form3;

Using react-dates with redux-form results in an error

I am trying to use react-dates with redux-form. Did a render thing for it. I have handled text input and select fields pretty much the same way. Those are working fine.
Getting a funky error on either DateRangePicker or even SingleDatePicker, which I cannot make sense of. Any ideas/suggestions are greatly appreciated.
Did a render component as:
const renderDateRangePicker = ({
input,
focusedInput,
onFocusChange,
startDatePlaceholderText,
endDatePlaceholderText
}) => (
<DateRangePicker
onDatesChange={(start, end) => input.onChange(start, end)}
onFocusChange={onFocusChange}
startDatePlaceholderText={startDatePlaceholderText}
endDatePlaceholderText={endDatePlaceholderText}
focusedInput={focusedInput}
startDate={(input.value && input.value.startDate) || null}
startDateId="startDateId"
endDateId="endDateId"
endDate={(input.value && input.value.endDate) || null}
minimumNights={0}
/>
)
My class is just a form as:
class ActivityForm extends Component {
// values: ['startDate', 'endDate']
state = {
focusedInput: null
}
onFocusChange(focusedInput) {
this.setState({ focusedInput });
}
render () {
const { focusedInput } = this.state
const { handleSubmit, teams } = this.props
return (
<form onSubmit={handleSubmit} className="activity__form">
<div className="activity__form_row">
<Field
name="name"
label="Activity name"
component={renderTextField}
margin="normal"
validate={[required]}
className="activity__form_field_name"
InputLabelProps={{
shrink: true,
}}
/>
<div className="activity__form_spacer"/>
<Field
name="daterange"
onFocusChange={this.onFocusChange}
focusedInput={focusedInput}
component={renderDateRangePicker}
/>
<div className="activity__form_spacer"/>
<Button className="activity__form_button" type="submit">Save</Button>
</div>
</form>
)
}
}
export default reduxForm({ form: 'activity' })(ActivityForm)
For some reason, DateRangePicker causes a strange error: Uncaught TypeError: Cannot read property 'createLTR' of undefined.
What am I missing?
I believe this error is caused by missing or misplaced import of the initialization of react-dates, you can take a look at the Initialize section in (https://github.com/airbnb/react-dates)
import 'react-dates/initialize';
It also looks like there is an update to DateRangePicker:
So include starteDateId and endDateId as props to the DateRangePicker component.
<DateRangePicker
startDateId="2" // PropTypes.string.isRequired,
endDateId="1" // PropTypes.string.isRequired,
startDate={this.props.filters.startDate}
endDate={this.props.filters.endDate}
onDatesChange={this.onDatesChange}
focusedInput={this.state.calendarFocused}
onFocusChange={this.onFocusChange}
showClearDates={true}
numberOfMonths={1}
isOutsideRange={() => false}
/>
It worked for me.

redux-form and react widgets' calendar - invalid prop value of type String

I want to use react-widgets calendar as input for start date and end date,
simplest implementation works:
const TripValidationForm = React.createClass({
FormDatepicker : ({input}) => {
return (<Calendar {...input} /> );
},
onSubmit : function(formData) {
const uid = this.props.auth.uid;
this.props.createTrip(formData, uid);
},
render : function() {
const {handleSubmit, submitting, feedback} = this.props;
return (
<div>
<form onSubmit={handleSubmit(this.onSubmit)} className="form-home">
<fieldset>
<Field name="startdate" valueField="value" component={this.FormDatepicker} />
<Field name="enddate" valueField="value" component={this.FormDatepicker}/>
</fieldset>
<p className="error">{feedback.msg}</p>
<button type="submit" className="btn btn-black" disabled={submitting}>Submit</button>
</form>
</div>
);
}
});
However following errors pop in my console, how I can prevent them from showing up?
looks like the warnings are coming from the props validation on the react widget calendar source, not much you can do unless you want to modify the source. Also this warnings are only shown in dev mode, if you bundle your code for production you shouldn't see any of this warnings
Found a solution, docs for a calendar widget say
The current selected date, should be a Date object or null.
So I used solution from one redux-form git-hub issues for datepicker
FormDatepicker : ({input}) => {
const selected = input.value ? new Date(input.value) : null;
return (<Calendar {...input} value={selected} /> );
}

Categories

Resources