I am attempting to integrate CKEditor into our React.js project, using the component found here: https://github.com/ckeditor/ckeditor5-react.
I have used this code in the git repository to define the CKEditor component:
https://github.com/ckeditor/ckeditor5-react/blob/master/src/ckeditor.jsx
And inside my code, I am referencing the component:
import CKEditor from '#ckeditor/ckeditor5-react';
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
const TemplateForm = props => {
return (
<div>
/* Other form fields */
<CKEditor
name="body"
placeholder="Compose message"
content={ props.defaults.body }
value={ props.defaults.body }
errors={ props.errors.body }
onInput={ props.onInput }
onChange={ props.onValueChange }
/>
</div>
);
};
When I load my page, I get a javascript error "Cannot read property 'create' of undefined" from ckeditor.js - the "this.props.editor" value is not defined. I'm a newbie to react, so I'm sure I'm just missing something pretty straightforward. Suggestions?
Your error is from the component (CKEditor) expecting a prop with the key 'editor', which you're not currently supplying.
You can probably find a list of options in their docs, but checking their repo I found this example where they're setting the editor to ClassicEditor which you're already importing:
https://github.com/ckeditor/ckeditor5-react/blob/master/sample/index.html
So this should work:
<CKEditor
name="body"
placeholder="Compose message"
content={ props.defaults.body }
editor={ ClassicEditor }
value={ props.defaults.body }
errors={ props.errors.body }
onInput={ props.onInput }
onChange={ props.onValueChange }
/>
Related
I'm using the following JSX code with a custom CKEditor that I built using the online-builder When I add this editor to my node modules and try to use it like the following:
import React, { Component } from 'react';
//import Editor from 'ckeditor5-custom-build/build/ckeditor';
import ClassicEditor from '#ckeditor/ckeditor5-build-custom';
import { CKEditor } from '#ckeditor/ckeditor5-react'
const editorConfiguration = {
toolbar: [ 'heading', '|', 'bold', 'italic', 'underline', 'strikethrough', '|' ]
};
class App extends Component {
render() {
return (
<div className="App">
<h2>Using CKEditor 5 from online builder in React</h2>
<CKEditor
editor={ ClassicEditor }
config={ editorConfiguration }
data="<p>Hello from CKEditor 5!</p>"
onReady={ editor => {
// You can store the "editor" and use when it is needed.
console.log( 'Editor is ready to use!', editor );
} }
onChange={ ( event, editor ) => {
const data = editor.getData();
console.log( { event, editor, data } );
} }
onBlur={ ( event, editor ) => {
console.log( 'Blur.', editor );
} }
onFocus={ ( event, editor ) => {
console.log( 'Focus.', editor );
} }
/>
</div>
);
}
}
export default App;
I get an error stating that TypeError: this.props.editor.create is not a function. Is there some step that I am apparently missing? The help is much appreciated.
After hours of research online and trying to figure out where the custom build went wrong it turned out to be the most simple solution ever! In my custom build's src folder where the ckeditor.js file is located (containing the custom build before being built) I noticed at the bottom of the file it looked something like this export default { Editor, Watchdog }; Seeing this I immediately knew the solution was to import the custom editor as a named import. If you import it as a default import then you will not have any of the features of the editor but rather the entire export as shown above. Simple solution change the line that says import ClassicEditor from '#ckeditor/ckeditor5-build-custom'; to import {Editor as ClassicEditor} from '#ckeditor/ckeditor5-build-custom'; and now it will import the way it was meant to be imported.The interesting part about this, is that if you do not add Watchdog to your custom build (using the online-builder) then it should be imported as a default import as it will export as follows export default Editor;
I am using CKEditor5 React Component Framework.I have successfully integrated the CKEditor in my project.And Being Able to use it.
But the problem is that I have to save the Content of the editor to the database and then display it to website.. All I get in the content
<blockquote><p>Hello from CKEditor 5!</p></blockquote>
And While Displaying it does not applies the css of CkEditor to show ..
Setup for CKEDITOR IS
import React, { Component } from 'react';
import CKEditor from '#ckeditor/ckeditor5-react';
import Classiceditor from '#ckeditor/ckeditor5-build-classic';
export class ClassicEditor extends Component {
constructor(){
super();
this.state = {
content : ""
}
}
onCashange = data => {
console.log( "Called" );
this.setState({
content : data.getData()
})
}
render() {
Classiceditor.builtinPlugins.map( plugin => console.log(plugin.pluginName) );
console.log("State", this.state.content);
return (
<>
<div className='App'>
<h2> Using CKEditor</h2>
<CKEditor
editor = { Classiceditor }
data = "<p>Hello from CKEditor 5!</p>"
onInit = { editor => {
//console.log( 'Editor is ready to use!', editor )
} }
onChange = { ( event, editor ) => {
this.onCashange( editor );
// const data = editor.getData();
// this.onChange( data );
// //console.log( { event, editor, data } );
}}
onBlur = { editor =>
console.log("Blur", editor) }
onFocus = { editor => {
//console.log( "Focus", editor )
} }
/>
</div>
<div className='editor'>
{ this.state.content }
</div>
</>
)
}
}
export default ClassicEditor
There are 2 options:
Download or using script to get Full CSS and include it in your project.
Link here
Note: You have to add a parent container with a class name ck-content
Create a custom CKEditor 5 build from the source code with all the CSS (both UI and the content) extracted to a separate file
Advance Guide
You can see more here from the documentation:
Content Styles
React does not allow you to render html code directly. Instead you have to use dangerouslySetInnerHTML attribute to do so. Do the following to solve your problem,
<div dangerouslySetInnerHTML={this.createMarkup()} className='editor'></div>
and have a method on the class as
createMarkup = () => {
return { __html: this.state.content };
}
This will make sure that you are not rendering the raw HTML to the page.
You can read more about this here
you can just install npm package like npm i react-render-html
enter link description here
and use it like :
<div className='...'>
{renderHTML(someHTML)}
</div>
Here is an answer to above question:
<div style={{wordWrap:'break-word',display:'inline-block'}}>
<div className="editor" dangerouslySetInnerHTML={{_html:this.state.content}}/>
</div>
I am trying to implement the standalone example from here, using react-popper - I basically just copy pasted the code for now. It does render the component. However, when I click everything breaks. I am using it in Gatsby.js - if that should make a difference?
That's the error(s) I'm getting:
index.js:2177 Warning: React.createElement: type is invalid --
expected a string (for built-in components) or a class/function (for
composite components) but got: undefined. You likely forgot to export
your component from the file it's defined in, or you might have mixed
up default and named imports.
Check your code at StandaloneExample.js:36.
And:
Uncaught TypeError: Object(...)(...) is not a function
at InnerPopper.render (Popper.js:159)
And:
The above error occurred in the component:
in InnerPopper (created by Context.Consumer)
in Popper (at StandaloneExample.js:34)
And multiple of these:
TypeError: Object(...)(...) is not a function
Here's my code:
import React, { PureComponent } from 'react'
import { Popper, Arrow } from 'react-popper'
import './popper.css'
class StandaloneExample extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOpen: false,
}
}
handleClick = (e) => {
console.log(e);
this.setState({
isOpen: !this.state.isOpen,
})
}
render() {
return (
<div>
<h2>Standalone Popper Example</h2>
<div
ref={div => (this.target = div)}
style={{ width: 120, height: 120, background: '#b4da55' }}
onClick={this.handleClick}
>
Click {this.state.isOpen ? 'to hide' : 'to show'} popper
</div>
{this.state.isOpen && (
<Popper className="popper" target={this.target}>
Popper Content for Standalone example
<Arrow className="popper__arrow" />
</Popper>
)}
</div>
)
}
}
export default StandaloneExample
I've modified things a bit (the way I implement state etc.), because I thought this might fix the errors I'm getting, but it didn't. Apart from that the code is pretty much the same as in the sandbox example - I'm not sure where it breaks.
edit: I am importing things like so:
import StandaloneExample from './MenuDropdown/StandaloneExample.js'
and am using it in my render function like so:
<StandaloneExample />
The example you linked is for react-popper#0.x.
Please check that you aren't with version 1 or greater.
react-popper V1 had breaking changes from V0.
You can find V1 doc here and V0 doc here.
The code is as follows.
import CKEditor from '#ckeditor/ckeditor5-react';
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
render() {
let selectedDocument = this.state.documentDetails;
return (
<div>
<div>
{
selectedDocument.html_content &&
<div className="form-group">
<CKEditor
editor={ ClassicEditor }
data={selectedDocument.html_content }
onInit={ editor => {
} }
onChange={ ( event, editor ) => {
const data = editor.getData();
let obj = {
target: {
name: 'html_content',
value: data
}
}
this.handleChange(obj);
} }
/>
</div>
}
</div>
</div>
);
}
Using the above code, the editor is displayed with basic toolbar buttons.
Now I need to add a new button to the toolbar which when clicked a javascript function needs to be called.
I have seen documentation on creating custom plugins, but I am not sure on how to implement this in the react way.
Any ideas on how to implement this? A sample piece of code would e really helpful.
Find config.js in CKEditor folder and update config.extraPlugins with your plugin like config.extraPlugins = 'html5video,widget,widgetselection,clipboard,lineutils,videoembed';
It will display new toolbar or button on CKEditor.
I've been playing around with draft-js by Facebook, but I can't actually figure out how to get the html output of the editor. The console.log in the following example outputs some _map properties, but they don't seem to contain my actual content?
class ContentContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
editorState: EditorState.createEmpty()
};
this.onChange = (editorState) => this.setState({editorState});
this.createContent = this.createContent.bind(this);
}
createContent() {
console.log(this.state.editorState.getCurrentContent());
}
render() {
const {editorState} = this.state;
const { content } = this.props;
return (
<Template>
<br /><br /><br />
<ContentList content={content} />
<div className="content__editor">
<Editor editorState={editorState} onChange={this.onChange} ref="content"/>
</div>
<FormButton text="Create" onClick={this.createContent.bind(this)} />
</Template>
);
}
}
There is a handy library I used, draft-js-export-html. Import the library and you should be able to see HTML once you invoke the function, stateToHTML:
console.log(stateToHTML(this.state.editorState.getCurrentContent()));
I'm pretty new to React so hopefully this works for you. I looked under the hood of contentState and there is a fair bit going on there that makes using a library to parse out the entities that much more enticing.
The author, sstur, answers a tangentially-related question where I learned about his libraries.
Ewan. I am also playing with Draft.js and came across the same problem. Actually, Victor has provided a great solution.
Here are two libraries that I found. The one mentioned by Victor has more stars on GitHub.
https://github.com/sstur/draft-js-export-html
https://github.com/rkpasia/draft-js-exporter
I just want to add that there is a way to print out the content (in JSON format) without using an external library. It is documented under the Data Conversion session.
Here is how I print out user input using the "convertToRaw" function
console.log(convertToRaw(yourEditorContentState.getCurrentContent()));
Make sure you imported the convertToRaw function from Draft.js by writing:
import { convertFromRaw, convertToRaw } from 'draft-js';
Here is a great blog written by rajaraodv named How Draft.js Represents Rich Text Data. It explained data conversion in detail.
There is readonly attribute to generate just HTML:
<Editor editorState={editorState} readOnly/>
If not willing to add another library to your code, #farincz's approach can work well.
<Editor editorState={this.state.editorState} readOnly/>
The editor state can be directly stored in your storage layer and when you are rendering it to the DOM it is easily available and can help in editing.
By clicking on the text you can make it editable, or bind that click with an edit button. You cannot directly bind click to 'Editor' component, but you can have it on the wrapper containing the 'Editor'.
<div className="editor" onClick={this.editContent.bind(this)}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
handleKeyCommand={this.handleKeyCommand}
readOnly={this.state.edit}
/>
</div>
Just add 'edit' to your state as true, making sure that readOnly is true (you can make the name 'edit' of the state more obvious, if it is confusing).
this.state = {
editorState: EditorState.createEmpty(),
edit: true
};
Finally change the value of 'edit' to false on click
editContent() {
this.setState({
edit: false
})
}
To expand on the libraries shared above, here's another good one : draftjs-to-html
It converts raw editor state (JSON object) into plain HTML.
import draftToHtml from 'draftjs-to-html';
import {convertToRaw} from "draft-js";
const rawContentState = convertToRaw(editorState.getCurrentContent());
const markup = draftToHtml(rawContentState);
The most suitable package to convert to HTML and from HTML is draft-convert
However, you should be aware to use the Advanced usage to be able to convert links and to customize the convert process:
const htmlResult = convertToHTML({
entityToHTML: (entity, originalText) => {
if (entity.type === 'LINK') {
return <a href={entity.data.url}>{originalText}</a>;
}
return originalText;
}
})(editorState.getCurrentContent());
const contentState = convertFromHTML({
htmlToEntity: (nodeName, node, createEntity): any | void => {
if (nodeName === 'a') {
return createEntity(
'LINK',
'MUTABLE',
{url: node.href}
)
}
}
})(htmlInput);