Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

draft.js - retrieve formatted text from db

My draft.js <TextEditor /> populates body with the text e.g: '{"blocks":[{"key":"3mont","text":"lorem ipsum","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}' and persists it to the db after using convertToRaw().

In Post.js, I want to retrieve and display the formatted text from the db. I've read that in order to do this, I must use convertToRaw() and then convertFromRaw() when retrieving it from the db but I'm having the same problems as this (I'm receiving the cors error and Unexpected token u in JSON at position 0) whenever I use convertFromRaw() and try to retrieve the formatted text from the db.

I've set up my server to support cors so why am I receiving the cors error? Is it because I am trying to parse an invalid response into JSON? How can I get the formatted text from the db in Post.js? Any help would be really appreciated!

GitHub

CreatePost.js

class CreatePost extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      title: "",
      body: EditorState.createEmpty(),
    };
  }

  changeHandler = (e) => {
    this.setState({ [e.target.name]: e.target.value });
  };

  submitHandler = (e) => {
    e.preventDefault();
    const {
      user: { _id },
    } = isAuthenticated();
    axios({
      url: `${API}/post/new-post/${_id}`,
      method: "POST",
      data: {
        ...this.state,
        body: JSON.stringify(convertToRaw(this.state.body.getCurrentContent())),
      },
    })
      .then((response) => {
      //  this.setState({ createdPost: this.state.title });
       return response
      })
      .catch((error) => {
        if (!this.state.title || !this.state.body) {
          this.setState({
            error: "This post must contain a title and a body.",
          });
        }
        console.log(error);
      });
  };

   // Attempt to map through blocks
   //getText = () => {
   // const {body} = this.state;
   //const arr = body.blocks.map(({ text }) => text).join(' ')
   // console.log(arr)
  //}

  render() {
    const { title, body } = this.state;

    return (
      <>
        <Navbar />
        <Tabs>
          <TabList>
            <Tab>Draft</Tab>
            <Tab>Preview</Tab>
          </TabList>
          <TabPanel>
            <div>
              <form onSubmit={this.submitHandler}>
                <div>
                // title input
                </div>
                <div>
                  <TextEditor
                    onChange={(value) => this.setState({ body: value })}
                    editorState={body}
                  />
                </div>
                <button type="submit">
                  Publish
                </button>
              </form>
            </div>
          </TabPanel>

          <TabPanel>
            <div>
              <h1>{title}</h1>
                // display body text value here too 
              {this.getText()}
            </div>
          </TabPanel>
        </Tabs>
      </>
    );
  }
}

Post.js (display body text)

  const [post, setPost] = useState({});
  const [error, setError] = useState(false);
  const id = props.match.params.id;

  const loadSinglePost = (slug, id) => {
    read(slug, id).then((data) => {
      if (error) {
        console.log(data.error);
        setError(data.error);
      } else {
        setPost(data)
        console.log(data);
      }
    });
  };

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

  return (
    <>
      <div>
        <h3>{post.title}</h3>
          ...
           // display text value below
          <p>{post.body}</p>
        </div>        
      </div>
    </>
  );
};

TextEditor.js

class TextEditor extends React.Component {
  constructor(props) {
    super(props);
    this.plugins = [addLinkPlugin];
  }
  toggleBlockType = (blockType) => {
    this.props.onChange(RichUtils.toggleBlockType(this.props.editorState, blockType));
  };
  handleKeyCommand = (command) => {
    const newState = RichUtils.handleKeyCommand(
      this.props.editorState,
      command
    );
    if (newState) {
      this.props.onChange(newState);
      return "handled";
    }
    return "not-handled";
  };

  onUnderlineClick = () => {
    this.props.onChange(
      RichUtils.toggleInlineStyle(this.props.editorState, "UNDERLINE")
    );
  };

  onBoldClick = (event) => {
    this.props.onChange(RichUtils.toggleInlineStyle(this.props.editorState, "BOLD"));
  };

  onItalicClick = () => {
    this.props.onChange(
      RichUtils.toggleInlineStyle(this.props.editorState, "ITALIC")
    );
  };

  onAddLink = () => {
    const editorState = this.props.editorState;
    const selection = editorState.getSelection();
    const link = window.prompt("Paste the link -");
    if (!link) {
      this.props.onChange(RichUtils.toggleLink(editorState, selection, null));
      return "handled";
    }
    const content = editorState.getCurrentContent();
    const contentWithEntity = content.createEntity("LINK", "MUTABLE", {
      url: link,
    });
    const newEditorState = EditorState.push(
      editorState,
      contentWithEntity,
      "create-entity"
    );
    const entityKey = contentWithEntity.getLastCreatedEntityKey();
    this.props.onChange(RichUtils.toggleLink(newEditorState, selection, entityKey));
  };

  toggleBlockType = (blockType) => {
    this.props.onChange(RichUtils.toggleBlockType(this.props.editorState, blockType));
  };

  render() {
    return (
      <div>
      // formatting buttons
        <div>
          <Editor
          blockStyleFn={getBlockStyle}
          editorState={this.props.editorState}
          handleKeyCommand={this.handleKeyCommand}
          onChange={this.props.onChange}
          plugins={this.plugins}
          placeholder="Post Content"
          />
        </div>
      </div>
    );
  }
}
like image 793
SK7 Avatar asked Nov 14 '20 14:11

SK7


1 Answers

Apparently draft-js does not have html output function because it's supposed to have no assumption on the output so people can tune their output however they want (see this). This means we'll have to implement it ourselves and if you're looking for just an html or markdown output to preserve in the database, then this mono repo can be of help. I've implemented an example of how to do it in this sandbox. Note that I used dangerouslySetInnerHTML for demonstration which is not optimal. You may want to use sanitization and rich text components to display back the posts. As a matter of fact I'd suggest ditching html and going for markdown instead if possible.

like image 108
Jackson Avatar answered Nov 12 '22 05:11

Jackson