Reputation: 13
I have a blog website built with Django and React. I'm currently working on adding a new blog post feature, and I want to allow users to select one or multiple categories for their blog post. Here's what I have done so far:
Fetched all the categories from the database and displayed them in a dropdown/select field.
Users can select one or multiple categories from the dropdown.
Now, I need help with the next steps. How can I send the selected categories to the database and save them for the new blog post? Any guidance or code examples would be greatly appreciated.
import React, { useEffect, useState } from 'react';
import Dashboard from './Dashboard';
import useAxios from '../../utils/useAxios';
function AuthorCreateBlogs() {
const baseurl = "http://127.0.0.1:8000/api/posts/v1";
const [selectedCategories, setSelectedCategories] = useState([]);
const api = useAxios();
const [categoriesData, setCategoriesData] = useState([]);
const [blogData, setBlogData] = useState({
"title": "",
"slug": "",
"body": "",
"tags": "",
"categories": [],
"img": "",
})
const handelInputChange = (event) => {
const { name, value } = event.target;
setBlogData((blogData) => ({
...blogData,
[name]: value
}));
};
const handleFileChange = (event) => {
setBlogData((blogData) => ({
...blogData,
['img']: event.target.files[0] // Match the key used in FormData
}));
};
const handleSubmit = (e) => {
e.preventDefault();
const form = {
'title': blogData.title,
'slug': blogData.slug,
'body': blogData.body,
'tags': blogData.tags,
'img': blogData.img,
'categories': blogData.categories,
'status': document.getElementById('status2').checked
}
console.log(form);
api.post(baseurl + '/author/posts/', form, {
headers: { "Content-Type": "multipart/form-data" },
})
.then(response => {
console.log('Post created:', response.data);
})
.catch(error => {
console.error('Error creating post:', error);
});
setBlogData({
"title": "",
"slug": "",
"body": "",
"tags": "",
"categories": "",
"img": "",
})
};
useEffect(() => {
api.get(baseurl + '/categories/') // Adjust the URL to your actual category endpoint
.then(response => {
setCategoriesData(response.data);
})
.catch(error => {
console.error('Error fetching categories:', error);
});
}, []);
return (
<div className='grid grid-cols-3 bg-gray-300'>
<div className='col-span-1'>
<Dashboard />
</div>
<div className='col-span-2 mr-24 mt-16'>
<div className="lg:ms-auto mx-auto text-center">
<div className="py-16 px-7 rounded-md bg-white">
<form action="" onSubmit={handleSubmit}>
<div className="grid md:grid-cols-2 grid-cols-1 gap-6">
<input
type="text"
id="fname"
name="title"
placeholder="Title"
value={blogData.title}
onChange={handelInputChange}
className="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:border-blue-700"
/>
<input
type="text"
id="fname"
name="slug"
placeholder="Slug"
value={blogData.slug}
onChange={handelInputChange}
className="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:border-blue-700"
/>
<div className="md:col-span-2">
<label htmlFor="categories" className="float-left block font-normal text-gray-400 text-lg">
Categories:
</label>
<select
id="subject"
name="categories"
onChange={handelInputChange}
className="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:border-blue-700"
>
<option value="" disabled selected>
Choose category:
</option>
{categoriesData?.map((category) => {
return (
<option key={category.id} value={category.id}>
{category.name}
</option>
)
})}
</select>
</div>
<div className="md:col-span-2">
<label htmlFor="file" className="float-left block font-normal text-gray-400 text-lg">
Image:
</label>
<input
type="file"
name='img' // Match the key in FormData
onChange={handleFileChange}
id="ProfileImage"
aria-describedby="emailHelp"
className="peer block w-full appearance-none border-none bg-transparent py-2.5 px-0 text-sm text-gray-900 focus:border-blue-600 focus:outline-none focus:ring-0"
/>
</div>
<div className="md:col-span-2">
<label htmlFor="status2" className="float-left block font-normal text-gray-400 text-lg">
Status:
</label>
<input
type="checkbox"
id="status2"
name="file"
className='transform scale-150'
/>
</div>
<div className="md:col-span-2">
<label htmlFor="subject" className="float-left block font-normal text-gray-400 text-lg">
Body:
</label>
<textarea
name="body"
rows="5"
cols=""
placeholder="Body..."
value={blogData.body}
onChange={handelInputChange}
className="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:border-blue-700"
></textarea>
</div>
<div className="md:col-span-2">
<textarea
name="tags"
rows="5"
cols=""
placeholder="Tags, please separate with ,"
value={blogData.tags}
onChange={handelInputChange}
className="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:border-blue-700"
></textarea>
</div>
<div className="md:col-span-2">
<button className="py-3 text-base font-medium rounded text-white bg-blue-800 w-full hover:bg-blue-700 transition duration-300">
Valider
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
);
}
export default AuthorCreateBlogs;
I can choose one category and send it to date base and create a post successfly but I want that user be able choose multyple item...
Upvotes: 0
Views: 58
Reputation: 314
There are multiple ways to do this;
import React from 'react';
import { Select, Typography } from 'antd';
const { Title } = Typography;
const options = [];
for (let i = 0; i < 100000; i++) {
const value = `${i.toString(36)}${i}`;
options.push({
label: value,
value,
disabled: i === 10,
});
}
const handleChange = (value) => {
console.log(`selected ${value}`);
};
const App = () => (
<>
<Title level={4}>{options.length} Items</Title>
<Select
mode="multiple"
style={{
width: '100%',
}}
placeholder="Please select"
defaultValue={['a10', 'c12']}
onChange={handleChange}
options={options}
/>
</>
);
export default App;
multiple
attribute to your select
tag like this <select
id="subject"
name="categories"
onChange={handelInputChange}
className="w-full border border-gray-300 rounded-md py-2 px-3 focus:outline-none focus:border-blue-700"
multiple // Added the multiple attribute here
>
but i think your handelInputChange
function on the select input will not allow accepting multiple options because your function setBlogData here
setBlogData((blogData) => ({
...blogData,
[name]: value
}));
is replacing the the old value with the a new one. Maybe create a new handler for the select input
const handelSelectInputChange = (event) => {
const { name, value } = event.target;
setBlogData((blogData) => ({
...blogData,
categories: value + old_value
}));
};
So the each new select does not replace the old one.
Upvotes: 0