Search code examples
mysqlnode.jsreactjsckeditor4.x

Why does my editable input fields submit empty strings if I edit only one of the input fields?


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;


Solution

  • 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}
    />