1

I'm using marked.js to create posts using markdown. The posts are created successfully with markdown and the html is being displayed however when I update / edit posts, sanitizedHtml is not being updated, it still contains the old content.

The other fields are being updated but sanitizedHtml is relying on the value from body and then converting it to html and sanitizing it in the back end.

Is sanitizedHtml not updating because I haven't set body to it in React and how can I solve it and get sanitizedHtml to update with the new value in body?

Post.js model

// ...
const marked = require("marked");
const createDomPurify = require("dompurify");
const { JSDOM } = require("jsdom");
const domPurify = createDomPurify(new JSDOM().window);

const postSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  body: {
    type: String,
    required: true,
  },
 // ...
  sanitizedHtml: {
    type: String,
    required: true,
  },
});

postSchema.pre("validate", function (next) {
  // markdown - sanitize and convert to html
  if (this.body) {
    this.sanitizedHtml = domPurify.sanitize(marked(this.body));
  }
  next();
});

EditPost.tsx

const EditPost = ({ match } : { match: any }) => {
  const [values, setValues] = useState({
    title: "",
    body: "",
    error: "",
    sanitizedHtml: "",
    updatedPost: "",
  });

  const [post, setPost] = useState({ title: values.title, body: values.body, sanitizedHtml: values.sanitizedHtml });
  const { token } = isAuthenticated();
  const { title, body, error, updatedPost, sanitizedHtml } = values;

  const init = (slug: string, id: number) => {
    read(slug, id).then((data) => {
      if (data.error) {
        setValues({ ...values, error: data.error });
      } else {
        setValues({ ...values, title: data.title, body: data.body, sanitizedHtml: data.sanitizedHtml });
        setPost({ title: values.title, body: values.body, sanitizedHtml: values.sanitizedHtml });
      }
    });
  };

  useEffect(() => {
    const id = match.params.id;
    const slug = match.params.slug
    init(slug, id);
  }, []);

  useEffect(() => {
    setPost({ ...values });
  }, [values.title, values.body, values.sanitizedHtml]);

  const handleChange = (name: string) => (event: any) => {
    setValues({ ...values, [name]: event.target.value });
  };

  const clickSubmit = (event: any) => {
    event.preventDefault();
    setValues({ ...values, error: "" });
    setPost({ title: values.title, body: values.body, sanitizedHtml: values.sanitizedHtml });

    editPost(match.params.userId, match.params.id, token, post).then((data) => {
      if (data.error) {
        setValues({ ...values, error: data.error });
      } else {
        setValues({
          ...values,
          title: data.title,
          body: data.body,
          sanitizedHtml: data.sanitizedHtml,
          updatedPost: data.title,
          error: "",
        });

        console.log(post);
        console.log(data);
      }
    });
  };

  const newPostForm = () => (
    <form onSubmit={clickSubmit}>
      <div>
        <input
          onChange={handleChange("title")}
          type="text"
          name="title"
          value={title}
        />
      </div>

      <div>
        <textarea
          onChange={handleChange("body")}
          value={body}
          name="body"
        />
      </div>

      <button type="submit">
        Publish
      </button>
    </form>
  );

  return (
    <>
    <div>
      {newPostForm()}
    </div>
    </>
  );
};

export default EditPost;

controllers/posts.js

exports.edit = (req, res) => {
  const id = req.params.id;
  if (!ObjectID.isValid(id))
    return res.status(400).send(`No post with given id: ${id}`);
  const { title, body, sanitizedHtml } = req.body;

  const updatedPost = { title, body, sanitizedHtml };
  Post.findByIdAndUpdate(
    id,
    {
      $set: updatedPost,
    },
    { new: true },
    (error, data) => {
      if (error) {
        return error;
      } else {
        res.send(data);
        console.log(updatedPost);
      }
    }
  );
};
Rahni
  • 451
  • 6
  • 20

1 Answers1

1

Solved it! I needed to use marked.js in the front end too.
I added the following code to convert the text area value to markdown and set that to sanitizedHtml in state:

let marked = require("marked");
sanitizedHtml: marked(values.body)
Rahni
  • 451
  • 6
  • 20