For a new project (next.js) I'd like to add an on submit handler to a form component and map the input of the form at the bottom of the page. However, I get the typeError message claiming that the "addSpending" is not a function.
Here the code for the form component:
import styled from "styled-components";
export default function NewSpendingForm({ addSpending }) {
function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const data = Object.fromEntries(formData);
addSpending(data);
}
return (
<StyledBody>
<StyledIntro>Please fill the form to add your spendings:</StyledIntro>
<StyledAddSpendingForm onSubmit={handleSubmit}>
<StyledFormLabel>Title</StyledFormLabel>
<StyledFormInput type="text" id="title" name="title" required />
<StyledFormLabel>Amount</StyledFormLabel>
<StyledFormInput type="number" id="amount" name="amount" step="0.01" min="0" required />
<StyledFormLabel>Date</StyledFormLabel>
<StyledFormInput type="date" id="date" name="date" required />
<StyledFormLabel>Category</StyledFormLabel>
<StyledFormSelect type="select" id="category" name="category" required >
<option>Food and Drinks</option>
<option>Clothes</option>
<option>Household</option>
<option>Entertainment</option>
<option>Gasoline</option>
<option>Restaurants</option>
<option>Others</option>
</StyledFormSelect>
<StyledFormButton type="submit">Submit</StyledFormButton>
</StyledAddSpendingForm>
</StyledBody>
);
}
And this one for the page:
import styled from "styled-components";
import NewSpendingForm from "../../components/AddSpendingForm";
export default function AddSpendingPage({ spendingInput, addSpendingInput }) {
return (
<>
<StyledHeader>
<StyledTitle>Add Spendings</StyledTitle>
</StyledHeader>
<StyledBody>
<NewSpendingForm addSpending={addSpendingInput} />
<StyledLogTitle> Your Spendings Log</StyledLogTitle>
<StyledLog>
{spendingInput.map((spendingInput) => (
<StyledLogEntry>
{spendingInput.title}
{spendingInput.amount}€
{spendingInput.date}
{spendingInput.category}
</StyledLogEntry>
))}
</StyledLog>
</StyledBody>
</>
);
}
Thanks a lot in advance!
I expected the form input to be mapped and displayed at the bottom of the page. However, after clicking on the "Submit" button I get the mentioned TypeError message.
Related
I'm running into an issue with adding my own custon input after following the documentation for Autocomplete.
The error I get is "this.props.contextValue.store.getState is not a function" when adding my CustomSearchBox component. Can anyone advise what I'm doing wrong?
Usage:
<InstantSearch
searchClient={algoliaClient}
indexName="plp"
>
<CustomSearchBox /> // Errors when I add this
<Autocomplete
searchClient={algoliaClient}
placeholder="Search products"
detachedMediaQuery="none"
openOnFocus
/>
<RefinementList attribute="DIAMETER" />
<HitWrapper>
<Hits hitComponent={Hit} />
</HitWrapper>
</InstantSearch>
Custom search box component
import React from 'react';
import { connectSearchBox } from 'react-instantsearch-dom';
const SearchBox = ({ currentRefinement, isSearchStalled, refine }) => (
<form noValidate action="" role="search">
<input
type="search"
value={currentRefinement}
onChange={event => refine(event.currentTarget.value)}
/>
{isSearchStalled ? 'My search is stalled' : ''}
</form>
);
const CustomSearchBox = connectSearchBox(SearchBox);
export default CustomSearchBox;
I have a simple component that looks like this :
function Checkboxes(props) {
return (
<div>
<input className="item-box-checkbox-1" type="checkbox" checked={getIsChecked(1, props)} />
<input className="item-box-checkbox-2" type="checkbox" checked={getIsChecked(2, props)} />
<input className="item-box-checkbox-3" type="checkbox" checked={getIsChecked(3, props)} />
<input className="item-box-checkbox-4" type="checkbox" checked={getIsChecked(4, props)} />
...
</div>
)
}
I would like to use Testing Library to "listen" on a checkbox click. As soon as the checkbox is checked I would like to proceed with my test.
Behind the scenes after checking on the checkbox some things are happening. After these things have happened then the checkbox should display as checked.
I have tried the following :
fireEvent.click(checkboxes[1]);
await screen.findAllByRole('checkbox', {checked: true})
But this does not seem to work.
There also seems to be a screen.getByRole("checkbox")).toBeChecked() . But I need to wait for the checkbox to be checked. screen.get* functions as I understand to not provide for this.
it is hard to tell what some things are happening but assuming we have sth like this:
import React from "react";
function Checkboxes(props) {
const [checked1, setCheck1] = React.useState(false);
const [checked2, setCheck2] = React.useState(false);
const [checked3, setCheck3] = React.useState(false);
const [checked4, setCheck4] = React.useState(false);
return (
<div>
<input className="item-box-checkbox-1" type="checkbox" onChange={setCheck1} checked={checked1} />
<input className="item-box-checkbox-2" type="checkbox" onChange={setCheck2} checked={checked2} />
<input className="item-box-checkbox-3" type="checkbox" onChange={setCheck3} checked={checked3} />
<input className="item-box-checkbox-4" type="checkbox" onChange={setCheck4} checked={checked4} />
</div>
)
}
export default Checkboxes;
Then your code work for me. You may also try to waitFor:
import { fireEvent, render, screen, waitFor } from '#testing-library/react';
import Checkboxes from "../Checkboxes";
it('should work', async () => {
render(<Checkboxes />);
const checkboxes = screen.getAllByRole('checkbox');
expect(checkboxes[1]).not.toBeChecked();
fireEvent.click(checkboxes[1]);
const checked = await screen.findAllByRole('checkbox', {checked: true})
expect(checked).toHaveLength(1);
await waitFor(() => expect(checkboxes[1]).toBeChecked())
})
I am using redux-form in order to submit a new user signup page in my React Web App, but when I try to grab the input field values on the form of the parameter values, it comes back undefined in mapDispatchToProps. I have read many posts of people claiming their values variable comes back undefined, but that is not the case for me. Only when I console.log(values.[inputName]) do I get undefined. According to the documentation, I cannot tell that I am doing anything incorrectly.
Can someone please help determine what is causing values.email to be undefined? Thanks.
// presentational component
class Signup extends Component {
render() {
const { handleSubmit } = this.props;
return (
<div>
<h1>Signup</h1>
<form onSubmit={handleSubmit}>
<div>
<label>
Email:
<Field component="input" type="email" name="email" />
</label>
</div>
<div>
<label>
Password:
<Field component="input" type="password" name="password" />
</label>
</div>
<button type="submit" >Submit</button>
</form>
</div>
)
}
}
export default reduxForm({
form: 'Signup',
enableReinitialize: true
})(Signup)
// redux container component
const mapDispatchToProps = (dispatch) => {
return {
handleSubmit: (values) => {
console.log(values.email); // outputs undefined!
}
};
}
const SignupContainer = connect(
null,
mapDispatchToProps
)(Signup)
export default SignupContainer;
// reducer index.js
import { reducer as formReducer } from 'redux-form';
export const appReducer = combineReducers({
form: formReducer
})
// store.js
export const store = createStore(
appReducer,
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
);
Side Note
I have noticed that whenever I first click the submit button on the form, the page refreshes (so I do not see the console.log). All proceeding times does not cause a refresh, but I am unsure as to why. Any explanation of this would be greatly appreciated, too.
Update
After changing my Router from HashHistory to BrowserRouter (react-router), the page refreshes every time I click submit. Seems that I have two problems now.
I have a form in a react component that has two change handlers, one for my two draftjs textareas, and one for my other text inputs:
onChangeEditor = (editorStateKey) => (editorState) => {
this.setState({ [editorStateKey]: editorState });
}
handleInputChange(event) {
event.preventDefault();
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
In my render method I have two views that I switch between depending on which view mode I am in, read or edit:
render () {
const Editable = () => (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" key="text01" name="title" defaultValue={this.state.title} onBlur={this.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.state.editorState1} onChange={this.onChangeEditor('editorState1')} name="text01"/>
<h4>Citat</h4>
<input type="text" key="text02" name="quote01" defaultValue={this.state.quote01} onBlur={this.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.state.editorState2} onChange={this.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.saveForm} />
</form>
</div>
);
const Readable = () => (
<div>
<h1 className="header66">{this.state.title}</h1>
<div className="text66">{this.state.text01}</div>
<div className="quote100">{this.state.quote01}</div>
<div className="text66">{this.state.text02}</div>
</div>
);
return (
<div>
{ this.props.isInEditMode ? <Editable /> : <Readable /> }
</div>
);
}
When I switch between inputs in my browser I have to click twice in order to get the focus on the right input.
I suspect that this is because a change is triggered on the "blur" event of each input, causing the form to rerender because state is changed. And when the form rerenders, it goes through the { this.props.isInEditMode ? <Editable /> : <Readable /> } which causes the input to lose focus.
The problem is that I don't know how to get around this.
I solved it myself.
It turns out that it was not a good idea to place the Editable and Readable inside of my component as I did. Instead I moved them out to their own components, and it works properly now.
class Editable extends React.Component {
render() {
return (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" name="title" defaultValue={this.props.title} onChange={this.props.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.props.editorState1} onChange={this.props.onChangeEditor('editorState1')} name="text01" />
<h4>Citat</h4>
<input type="text" name="quote01" defaultValue={this.props.quote01} onChange={this.props.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.props.editorState2} onChange={this.props.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.props.saveForm} />
</form>
</div>
);
}
};
class Readable extends React.Component {
render() {
return (
<div>
<h1 className="header66">{this.props.title}</h1>
<div className="text66">{this.props.text01}</div>
<div className="quote100">{this.props.quote01}</div>
<div className="text66">{this.props.text02}</div>
</div>
);
}
};
I am encountering a strange problem when declaring a Field of type number and using the example renderField component on the redux-form website.
const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type}/>
{touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))}
</div>
);
Inside my render, I have a component of type number with a step size
<Field name="SmallStepSizeNumber" type='number' step={0.000001}
component={renderField} label="SmallStepSizeNumber"
validate={[ ]}
/>
All I'm trying to replicate is a normal html step size change, but it just steps by 1 ignoring my step size. The same happens when I try to set min/max/etc. Am I specifying this wrong? Is this a bug?
Passing a string instead of a number might works
const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
<div>
<input type="number" {...input} step="0.1" />
</div>
);
const Form = () => (
<Field
name="foobar"
component={renderField}
/>
);
Here's a jsfiddle https://jsfiddle.net/75rh036o/12/