I have a validation for fields in the form:
const [orderForm, setOrderForm] = React.useState({
title: {
elementType: 'input',
label: 'Title',
elementConfig: {
type: 'text',
placeholder: 'Title'
},
value: '',
validation: {
required: true
},
valid: false,
touched: false
},
price: {
elementType: 'input',
label: 'Price',
elementConfig: {
type: 'text',
placeholder: 'Price'
},
value: '',
validation: {
required: true,
isNumeric: true
},
valid: false,
touched: false
},
category: {
elementType: 'select',
label: 'Select category',
defaultValue: 'Select category',
value: '',
validation: {
required: false
},
valid: false,
touched: false
},
description: {
elementType: 'textarea',
label: 'Description',
elementConfig: {
type: 'text',
placeholder: 'Description'
},
value: '',
validation: {
required: true
},
valid: false,
touched: false
},
});
I faced the problem that I should add one more input field for image upload. I have this code for image upload (now it separated from my validation construction):
const [pickedImage, setPickedImage] = React.useState("");
const handleClick = () => { imageInput.current.click();};
const handleChange = () => {
const file = imageInput.current.files[0];
const reader = new FileReader();
reader.onload = (event) => {
setPickedImage(event.target.result);
};
if (file) {
reader.readAsDataURL(file);
}
};
<input type="file" name="image" className="imageInput" ref={imageInput} onChange={handleChange} accept=".jpg,.png,.jpeg" />
<button className="button-empty" onClick={handleClick}>Choose Image</button>
Because it separated I do not understand how to make my button Add product make active only when user attached the image.
This is the whole code:
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Header } from '../components/Header';
import { LeftMenu } from '../components/LeftMenu';
import * as categoriesActions from '../store/actions/categories';
import * as productsActions from '../store/actions/products';
import { updateObject, checkValidity } from '../utility/utility';
import Input from '../components/UI/Input/Input';
import Button from '../components/UI/Button/Button';
import { useHistory } from 'react-router-dom';
export const AddProduct = props => {
const dispatch = useDispatch();
let history = useHistory();
const userId = '5fe99c69488a0f6307df5990';
// const userId = useSelector(state => state.auth.userId);
const categories = useSelector(state => state.categories.categories);
React.useEffect(() => {
dispatch(categoriesActions.fetchCategories());
}, [dispatch]);
const [pickedImage, setPickedImage] = React.useState("");
const imageInput = React.useRef();
const handleClick = () => {
imageInput.current.click();
};
const handleChange = () => {
const file = imageInput.current.files[0];
const reader = new FileReader();
reader.onload = (event) => {
setPickedImage(event.target.result);
};
if (file) {
reader.readAsDataURL(file);
}
};
React.useEffect(() => {
setOrderForm((oldValue) => ({
...oldValue,
category: {
...oldValue.category,
elementConfig:
categories.map((category) => (
<>
<option hidden>Choose category</option>
<option key={category._id} value={category._id}>
{category.title}
</option>
</>
)),
}
}));
}, [categories])
const [orderForm, setOrderForm] = React.useState({
title: {
elementType: 'input',
label: 'Title',
elementConfig: {
type: 'text',
placeholder: 'Title'
},
value: '',
validation: {
required: true
},
valid: false,
touched: false
},
price: {
elementType: 'input',
label: 'Price',
elementConfig: {
type: 'text',
placeholder: 'Price'
},
value: '',
validation: {
required: true,
isNumeric: true
},
valid: false,
touched: false
},
category: {
elementType: 'select',
label: 'Select category',
defaultValue: 'Select category',
value: '',
validation: {
required: false
},
valid: false,
touched: false
},
description: {
elementType: 'textarea',
label: 'Description',
elementConfig: {
type: 'text',
placeholder: 'Description'
},
value: '',
validation: {
required: true
},
valid: false,
touched: false
},
});
const [formIsValid, setFormIsValid] = React.useState(false);
//Submit form data
const orderHandler = event => {
event.preventDefault();
const formData = {};
for (let formElementIdentifier in orderForm) {
formData[formElementIdentifier] = orderForm[formElementIdentifier].value;
}
const product = {
userId: userId,
title: formData.title,
price: formData.price,
description: formData.description,
category: formData.category,
imageUrl: pickedImage
};
dispatch(productsActions.addProduct(product));
history.push('/products');
};
//onChange Data
const inputChangedHandler = (event, inputIdentifier) => {
const updatedFormElement = updateObject(orderForm[inputIdentifier], {
value: event.target.value,
valid: checkValidity(
event.target.value,
orderForm[inputIdentifier].validation
),
touched: true
});
const updatedOrderForm = updateObject(orderForm, {
[inputIdentifier]: updatedFormElement
});
let formIsValid = true;
for (let inputIdentifier in updatedOrderForm) {
formIsValid = updatedOrderForm[inputIdentifier].valid && formIsValid;
}
setFormIsValid(formIsValid);
setOrderForm(updatedOrderForm);
};
const formElementsArray = [];
for (let key in orderForm) {
formElementsArray.push({
id: key,
config: orderForm[key]
});
}
let form = (
<form class="row" onSubmit={orderHandler}>
<div class="item--1-4 image-block">
<div class="product-image-group">
{pickedImage ? (
<img onClick={handleClick} src={pickedImage} alt="preview" />
) : (
<div onClick={handleClick} class="image-round-cover">
<ion-icon name="person-outline"></ion-icon>
</div>
)}
<input
type="file"
name="image"
className="imageInput"
ref={imageInput}
onChange={handleChange}
accept=".jpg,.png,.jpeg"
/>
<button className="button-empty" onClick={handleClick}>
Choose Image
</button>
</div>
</div>
<div class="item--3-4">
<div class="item-title">
<h3>Add product</h3>
<hr class="border-divider" />
</div>
{formElementsArray.map(formElement => (
<div class="group-fields">
< Input
key={formElement.id}
class={formElement.config.className}
ref={formElement.config.ref}
elementType={formElement.config.elementType}
elementConfig={formElement.config.elementConfig}
value={formElement.config.value}
invalid={!formElement.config.valid}
shouldValidate={formElement.config.validation}
touched={formElement.config.touched}
changed={event => inputChangedHandler(event, formElement.id)}
/>
</div>
))}
<div class="item-footer">
<Button btnType="Success" disabled={!formIsValid}>
Add product
</Button>
</div>
</div>
</form>
);
if (props.loading) {
// form = <Spinner />;
}
return (
<div class="wrapper">
<Header />
<article class="main">
{form}
</article>
<LeftMenu />
</div>
);
};
Thank you for any support.