I'm trying to create a very simple Content Management System for creating and updating blog posts. I managed to successfully create and delete blog posts but I'm having difficulty wrapping my head around when I try to edit them.
The problem I'm running into is if I have 3 fields that are Editable for the Blog Post.
1) Blog Topic 2) Blog Picture 3) Blog Content
If I edit 1 field such as Blog Topic
with test data and I submit the changes, the data that was in Blog Picture and Blog Content get lost and submit nothing even though there was data there previously and I'm not sure why. However, if I set the defaultValue
to my state whenever I save to make changes, the problem gets fixed but I want my inputs to have the initial value in there field also.
Here is my code:
import React from "react";
import ReactDOM from "react-dom";
import Header from "../common/Header";
import Footer from "../common/Footer";
import Adminediting from "../common/isEditing";
import Addblogtopic from "./Addblogtopic";
import { Modal, Button } from "react-bootstrap";
import { Link, Redirect } from "react-router-dom";
import Moment from "moment";
import dataTip from "data-tip";
import { confirmAlert } from "react-confirm-alert";
import CKEditor from "ckeditor4-react";
import blogtopicsService from "../../services/Blogservice";
import appController from "../../controllers/appController";
class Blogtopics extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
blogData: [],
blogCategory: "",
blogContent: "",
blogId: "",
hoverSelected: false,
isEditing: false,
fileObject: "",
fileName: "",
fileSize: "",
fileType: "",
filePayload: "",
blogPicture: "",
email: "",
firstName: "",
lastName: "",
roleId: "",
userId: "",
errorMsg2: false,
errorMsg3: false
};
}
Selectblogtopics = async () => {
const blogTopics = await blogtopicsService.selectblogTopics();
this.setState({
blogData: blogTopics
});
};
toggleHover = hoverState => {
this.setState({ hoverSelected: hoverState });
};
updateImage = e => {
let file = e.target.files[0];
var dataTypeURL = new FileReader();
var arrayBuffer = new FileReader();
this.setState({
fileObject: file,
fileName: file.name,
fileSize: file.size,
fileType: file.type
});
dataTypeURL.onload = e => {
this.setState({
filePayload: e.target.result,
blogPicture: e.target.result
});
};
dataTypeURL.readAsDataURL(file);
arrayBuffer.readAsArrayBuffer(file);
};
editBlog = editingState => {
this.setState({
isEditing: !editingState
});
//Publish Changes
setTimeout(async () => {
this.setState({
isLoading: false
});
const uploadData = {
blogCategory: this.state.blogCategory,
blogContent: this.state.blogContent,
modifiedDate: Moment().format("YYYY-MM-DD hh:mm:ss"),
blogId: this.state.blogId,
fileType: this.state.fileType,
fileName: this.state.fileName,
fileSize: this.state.fileSize,
filePayload: this.state.filePayload
};
const updateBlog = await blogtopicsService.editBlog(uploadData);
location.href = "/blog";
}, 1000);
}
};
handleClose = () => {
this.setState({ show: false });
};
handleShow = () => {
this.setState({ show: true });
};
onChange = async (e, blogId) => {
await this.setState({
[e.target.name]: e.target.value,
blogId: blogId
});
};
deleteBlog = blogId => {
confirmAlert({
customUI: ({ onClose }) => {
return (
<div className="custom-ui">
<h1>Are you sure</h1>
<p>You want to delete this blog?</p>
<button onClick={onClose}>Cancel</button>
<button
onClick={() => {
this.confirmDelete(blogId);
onClose();
}}
>
Confirm
</button>
</div>
);
}
});
};
confirmDelete = async blogId => {
// Delete the blog
const deleteBlog = await blogtopicsService.deleteBlog({ blog_id: blogId });
// Re-render the blog posts after deleting
await this.Selectblogtopics();
};
async componentDidMount() {
await this.userData();
await this.Selectblogtopics();
}
render() {
return (
<div className="fluid-container">
<div className="blogContainer">
<Header />
<Adminediting
title={this.props.match.path}
editState={this.editBlog}
/>
<div className="container">
<div className="editSection">
<div className="text-right">
<span className="data-tip-bottom" data-tip="Add Blog Post">
<i className="fas fa-plus" onClick={this.handleShow} />
</span>
</div>
</div>
<div className="blogContent">
{this.state.blogData.map((rows, index) => (
<div className="blogWrapper" key={index}>
{rows.blog_status === 1 ? (
<div
className="row"
>
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add Blog Post</Modal.Title>
</Modal.Header>
<Modal.Body>
<Addblogtopic
handleClose={this.handleClose}
selectblogTopics={this.Selectblogtopics}
/>
</Modal.Body>
</Modal>
<div className="col-md-4">
<img
src={
"https://s3-us-east-1.amazonaws.com/" +
rows.blog_thumbnail
}
alt="test"
/>
{this.state.isEditing === true ? (
<div className="input-group">
<input
type="file"
className="d-block mt-4"
name="blogPicture"
onChange={e => this.updateImage(e)}
/>
</div>
) : null}
</div>
<div className="col-md-6">
{this.state.isEditing === true ? (
<input
type="text"
name="blogCategory"
onChange={e => this.onChange(e, rows.blog_id)}
defaultValue={rows.blog_category}
/>
) : (
<Link
to={
"/blog/" +
rows.blog_id +
"/" +
appController.friendlyUrl(rows.blog_category)
}
id="blogUrl"
>
<h3
id="blogTopic"
dangerouslySetInnerHTML={{
__html: rows.blog_category
}}
/>
</Link>
)}
{this.state.roleId === 1 ? (
<div className="editSection">
<div className="text-right">
<span
className="data-tip-bottom"
data-tip="Delete Blog Post"
>
<i
className="far fa-trash-alt"
onClick={e => this.deleteBlog(rows.blog_id)}
/>
</span>
</div>
</div>
) : null}
<div
className={
this.state.hoverSelected == index
? "blogSection hover"
: "blogSection"
}
>
{this.state.isEditing === true ? (
<CKEditor
data={rows.blog_content}
onChange={(event, editor) => {
const data = event.editor.getData();
this.setState({
blogContent: data
});
}}
/>
) : rows.blog_content.length > 50 ? (
<div
className="cmsStyles"
dangerouslySetInnerHTML={{
__html: rows.blog_content.substr(0, 50) + " ..."
}}
/>
) : (
<div
className="cmsStyles"
dangerouslySetInnerHTML={{
__html: rows.blog_content
}}
/>
)}
</div>
</div>
</div>
) : null}
</div>
))}
</div>
</div>
</div>
<Footer />
</div>
);
}
}
export default Blogtopics;
Back End Data
var db = require("../dbconnection");
const AWS = require("aws-sdk");
var blog = {
insertblogPost: function(data, callback) {
var uniquePicture = "blogphoto" + "-" + data.fileName;
var awsFolder = "awsfolder" + "/" + uniquePicture;
db.query(
"insert blog_topics set blog_category=?, blog_thumbnail=?, blog_content=?, blog_author=?",
[data.blogTopic, uniquePicture, data.blogContent, "random user"]
);
var buf = new Buffer(
data.filePayload.replace(/^data:image\/\w+;base64,/, ""),
"base64"
);
//Upload file into AWS S3 Bucket
var s3 = new AWS.S3();
var params = {
Bucket: "testbucket",
Key: awsFolder,
Body: buf,
ContentType: data.fileType,
ACL: "public-read"
};
s3.putObject(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
return data;
}
}),
callback(true);
},
deleteBlog: function(data, callback) {
db.query(
"UPDATE blog_topics set blog_status=? where blog_id=?",
["0", data.blog_id],
callback
);
},
editBlog: function(data, callback) {
var uniquePicture = "blogphoto" + "-" + data.fileName;
var awsFolder = "awsfolder" + "/" + uniquePicture;
db.query(
"UPDATE blog_topics set blog_category=?, blog_thumbnail=?, blog_content=?, blog_author=?, modified_date=? where blog_id=?",
[
data.blogCategory,
uniquePicture,
data.blogContent,
"Test Username",
data.modifiedDate,
data.blogId
]
);
var buf = new Buffer(
data.filePayload.replace(/^data:image\/\w+;base64,/, ""),
"base64"
);
//Upload file into AWS S3 Bucket
var s3 = new AWS.S3();
var params = {
Bucket: "awsbucket",
Key: awsFolder,
Body: buf,
ContentType: data.fileType,
ACL: "public-read"
};
s3.putObject(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
return data;
//console.log(data);
}
}),
callback(true);
},
selectblogTopics: function(data, callback) {
db.query(
"select blog_id, blog_category, blog_thumbnail, blog_content, blog_status, blog_author, created_date, modified_date from blog_topics",
callback
);
},
selectblogArticle: function(data, callback) {
db.query(
"select blog_id, blog_category, blog_thumbnail, blog_content, blog_author, created_date from blog_topics where blog_id=?",
[data.blogId],
callback
);
},
editArticle: function(data, callback) {
var uniquePicture = "blogphoto" + "-" + data.fileName;
var awsFolder = "awsfolder" + "/" + uniquePicture;
db.query(
"UPDATE blog_topics set blog_category=?, blog_thumbnail=?, blog_content=?, blog_author=?, modified_date=? where blog_id=?",
[
data.blogCategory,
uniquePicture,
data.blogContent,
"test user",
data.modifiedDate,
data.blogId
]
);
var buf = new Buffer(
data.filePayload.replace(/^data:image\/\w+;base64,/, ""),
"base64"
);
//Upload file into AWS S3 Bucket
var s3 = new AWS.S3();
var params = {
Bucket: "awsfolder",
Key: awsFolder,
Body: buf,
ContentType: data.fileType,
ACL: "public-read"
};
s3.putObject(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
return data;
}
}),
callback(true);
}
};
module.exports = blog;
You can create a generic method to update all blog info.
setBlogProperty(index, propName, propValue) {
this.setState(state => {
state.blogData[index][propName] = propValue;
return state;
});
};
Then call this method on onChange
event of your input element.
<input
type="text"
name="blogCategory"
onChange={e => this.setBlogProperty(index, 'blog_category', e.target.value)}
defaultValue={rows.blog_category}
/>