Using Classic CKEditor5 with Form Control react bootstrap - javascript

Hello Guys I'm very new in web developing and I want to try implementing rich text editor (I'm Using Classic CKEditor 5) with Form Control from react-bootstrap but When I wrap it with the Form.Control it not appear and showing error in the console
I Try this but it shows error
<Form.Control>
<CKEditor
editor={ClassicEditor}
data={value}
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 });
onChangeText(data);
}}
onBlur={(event, editor) => {
console.log('Blur.', editor);
}}
onFocus={(event, editor) => {
setShowErr(true);
}}
/>
</Form.Control>
This was my alternative I use border color but it not pleasant (but working) it showing color when invalid
<div className={`${showErr && isInvalid ? 'container' : ''} `}>
<CKEditor
editor={ClassicEditor}
data={value}
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();
onChangeText(data);
}}
onBlur={(event, editor) => {
console.log('Blur.', editor);
}}
onFocus={(event, editor) => {
setShowErr(true);
}}
/>
</div>
I expect when I type nothing in ckeditor it will show error with react bootstrap form. Thanks again

Related

Attribute is not saved in Gutenberg

I am trying to create a custom block for Wordpress Gutenberg.
I have the following attributes:
"icon": {
"type": "object",
"source": "html",
"selector": ".jig_defbox-icon"
},
"color": {
"type": "string",
"default": "#919191"
}
In my EditJS I try to store values from a color-picker and a radiogroup into these attributes.
const [ toggled, setToggled ] = useState( );
return(
<InspectorControls>
<ColorPalette
colors={[
{name: 'lightgray', color: '#d8d8d8'},
{name: 'darkgray', color: '#919191'},
{name: 'red', color: '#dc1a22'}
]}
disableCustomColors={true}
onChange={(value) => {props.setAttributes({color: value});}}
value={props.attributes.color}
clearable={false}
/>
<RadioGroup
onChange={ (value) => {setToggled(value);props.setAttributes({icon: value});} }
checked={props.attributes.icon}
>
{
str_array.map(
item => ( <Radio value={item}><Icon icon={icon_getter(item);}/></Radio>)
)
}
</RadioGroup>
</InspectorControls>
)
In my SaveJS I try to render my markup according to these attributes:
const {attributes} = props
<div style={{"fill": attributes.color}}>
<Icon icon={icon_getter(attributes.icon)}/>
</div>
The goal is to render an svg-icon according to the selection on my radiogroup.
Issue 1: Every new edit-session in backend, the selection of my radiogroup is gone, even with useState (tried without useState first)
Issue 2: Every new edit-session, a console error is logged, that says that the post-body markup does not match the markup returned by the save function, because the save-markup does not contain the icon attribute content
As far as I was able to enclose the problem, the icon attribute is not correctly saved. I tried to save the "key" for the icon as a string and object. If I log the value in the save function, it is empty, while the selected color works as expected, both in frontend and backend.
I was able to fix it via rethinking my concept of fetching the icon.
Apparently, Gutenberg tried to store the code of the icon into the database, but not the key. When loading the backend editor, the icon_getter function received a null value, therefore, the difference between post body and save function code.
I changed my editJS:
<RadioGroup
onChange={ (value) => {props.setAttributes({icon: value});} }
checked={props.attributes.icon}
>
{
my_icons_as_list.map(
item => ( <Radio value={item}><Icon icon={my_icons[props.attributes.icon];}/></Radio>)
)
}
</RadioGroup>
and my saveJS:
<Icon icon={ my_icons[ attributes.icon ] } />

How to display data fetched from Wordpress RestAPI in html format using React?

Using React, I am trying to get page data from a WordPress API.
pic of my current output
As you can see, the date and title data are displayed normally but the excerpt is not rendered properly. I am not sure how I can fix that.
Below is the code I use to fetch and display the data:
To fetch the data:
//fetching the pages
useEffect( ()=>{
Axios.get("https://www.eswaran.no/wp-json/wp/v2/pages").
then(response => {
setPosts(response.data);
}, [posts, setPosts]);
})
To display the data:
<div className="page-list">
{posts && posts.length && posts.map((post, index) => {
return (
<div key={post.id} className="page">
<h2>{post.title.rendered}</h2>
<h4>{moment(post.date).format('Do MMMM YYYY')}</h4>
<div dangerouslySetInnerHTML={{ __html: post.excerpt.rendered}} />
Go to page
</div>
);
})}
</div>
Ok your Api is well returning the data.
So in order to just remove the brackets, you can use regex :
{posts && posts.length && posts.map((post, index) => {
const cleanExcerpt = post.excerpt.rendered.replace(/\[([^\[])*(\])/g, '');
return (
<div key={post.id} className="page">
<h2>{post.title.rendered}</h2>
<h4>{moment(post.date).format('Do MMMM YYYY')}</h4>
<div dangerouslySetInnerHTML={{ __html: cleanExcerpt }} />
Go to page
</div>
);
})}

Material ui Autocomplete: can tags be created on events aside from 'Enter' events?

I am currently working with the freesolo Autocomplete and my particular use case requires tags to be created when commas or spaces follow the input text. Autocomplete currently creates tags on the Enter event, but I don't think there is anything built into Autocomplete yet that supports tag creation on any other event. I'm wondering if I'm missing anything, or if I'm not, how could I approach this problem?
Currently, I'm attempting to use the onInputChange attribute in Autocomplete to capture the string coming in. I check that string for commas and spaces, and on a successful find of one of those characters I manually fire off the Enter event using some native JS code. This works in some cases, but not in all cases and accounting for all cases is becoming tedious. This approach seems like it's prone to a lot of issues, and I'm not convinced it's the best way to go about implementing tag creation on different events. Looking for some thoughts. Thanks
onInputChange attribute usage:
<Autocomplete
multiple
freeSolo
filterSelectedOptions
id="auto-complete"
options={foo.map(bar => bar.name)}
ref={autoRef}
onInputChange={(e, value) => {
createTagOnEvent(value);
}}/>
Searching through input for commas and spaces and firing off Enter event manually:
const createTagOnEvent = (bar) => {
if (pattern.test(bar)) {
const ke = new KeyboardEvent("keydown", {bubbles: true, cancelable: true, keyCode: 13});
autoRef.current.dispatchEvent(ke);
}
};
Below is the approach I would recommend.
There are two main aspects to the approach:
Use a "controlled" input approach for the Autocomplete so that you have full control over the current value.
Specify the onKeyDown handler for the TextField input via params.inputProps.onKeyDown with appropriate logic for adding the new value.
import React from "react";
import TextField from "#material-ui/core/TextField";
import Autocomplete from "#material-ui/lab/Autocomplete";
export default function Tags() {
const [value, setValue] = React.useState([top100Films[13]]);
const handleKeyDown = event => {
switch (event.key) {
case ",":
case " ": {
event.preventDefault();
event.stopPropagation();
if (event.target.value.length > 0) {
setValue([...value, event.target.value]);
}
break;
}
default:
}
};
return (
<div style={{ width: 500 }}>
<Autocomplete
multiple
freeSolo
id="tags-outlined"
options={top100Films}
getOptionLabel={option => option.title || option}
value={value}
onChange={(event, newValue) => setValue(newValue)}
filterSelectedOptions
renderInput={params => {
params.inputProps.onKeyDown = handleKeyDown;
return (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
margin="normal"
fullWidth
/>
);
}}
/>
</div>
);
}
// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
const top100Films = [
{ title: "The Shawshank Redemption", year: 1994 },
{ title: "The Godfather", year: 1972 },
// ... many more options
];
Here's a Typescript version:
/* eslint-disable no-use-before-define */
import React from "react";
import TextField from "#material-ui/core/TextField";
import Autocomplete, { RenderInputParams } from "#material-ui/lab/Autocomplete";
interface ObjectOption {
title: string;
year: number;
}
type Option = ObjectOption | string;
interface MyInputProps {
onKeyDown: (event: object) => void;
}
interface MyParams extends RenderInputParams {
inputProps: MyInputProps;
}
export default function Tags() {
const [value, setValue] = React.useState([top100Films[13]]);
const handleKeyDown = event => {
switch (event.key) {
case ",":
case " ": {
event.preventDefault();
event.stopPropagation();
if (event.target.value.length > 0) {
setValue([...value, event.target.value]);
}
break;
}
default:
}
};
return (
<div style={{ width: 500 }}>
<Autocomplete
multiple
freeSolo
id="tags-outlined"
options={top100Films}
getOptionLabel={option => {
if (typeof option === "string") {
return option;
}
return option.title;
}}
value={value}
onChange={(event, newValue) => setValue(newValue)}
filterSelectedOptions
renderInput={(params: MyParams) => {
params.inputProps.onKeyDown = handleKeyDown;
return (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
margin="normal"
fullWidth
/>
);
}}
/>
</div>
);
}
// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
const top100Films: ObjectOption[] = [
{ title: "The Shawshank Redemption", year: 1994 },
{ title: "The Godfather", year: 1972 },
// ... many more options
];
As answered here, just use the autoHighlight flag:
<Autocomplete autoHighlight {...} />
It will highlight the first option by default, so pressing enter will select it.

How to fix redux-form "validate" when rendering an input from a variable in react-admin?

So I'm using a custom-built dialog component in react-admin which has a SimpleForm inside it. When I try to use input-level validate attribute on a LongTextInput, it just doesn't work. There is no error in the console or anything like that, but the input just accepts the text as is without validation. I don't seem to understand where I'm going wrong.
In the code that you see below, the inputs in the form that I have to render are conditional based on the props I'm passing from the parent. Hence, creating the form in a variable and then rendering it in the return() method.
What I've tried is rendering the inputs directly in the return() method without using the variable, but that does not seem to fix the validation problem as well.
Here's the array that defines the validation parameters I want to use -
const validateReason = [required(), minLength(5), maxLength(100)];
And I'm using this in the below render() method -
render() {
const props = this.props;
let renderForm = null;
if(props.formType === 'reject') {
renderForm =
(<SimpleForm
form="form"
toolbar={null}>
<RadioButtonGroupInput onChange={this.handleChoiceChange} source="reason" choices={[
{ id: '1', name: 'Inappropriate' },
{ id: '2', name: 'Abusive' },
{ id: '3', name: 'Not Product Related' },
{ id: '4', name: 'Others' },
]} />
<FormDataConsumer label="Select L2 Category" alwaysOn>
{({ formData }) => formData.reason === '4' &&
<LongTextInput
defaultValue={this.state.reasontext}
onChange={this.handleReasonChange}
source="reason_text"
label={props.title}
validate={validateReason}
/>
}
</FormDataConsumer>
</SimpleForm>);
}
else if(props.formType === 'skip') {
renderForm =
(<SimpleForm
form="form"
toolbar={null}>
<LongTextInput
defaultValue={this.state.reasontext}
onChange={this.handleReasonChange}
source="reason_text"
label={props.title}
validate={validateReason}
/>
</SimpleForm>);
}
return (
<Fragment>
<Dialog
fullWidth
open={props.showDialog}
aria-label={props.title}
>
<DialogTitle>{props.title}</DialogTitle>
<DialogContent>
{renderForm}
</DialogContent>
<DialogActions>
<SaveButton
onClick={() => {
props.handleClose();
this.handleSaveClick(props.formType);
}}
label={props.positiveButtonText}
/>
<Button onClick={() => {
this.clearReason();
props.handleClose();
}}>
Cancel
</Button>
</DialogActions>
</Dialog>
</Fragment>
);
}
I expect that the validate attribute validates my input correctly according to my validation parameters.

How do I display the content of React Quill without the html markup?

I managed to get my Quill working, but now I wanted to make a nice splitscreen as we have on this forum but one thing I haven't been able to figure out is how to convert the input of Quill to nice text on the preview side.
I'm able to display the text but it still has all the html tags which of course I don't want.
So this is my Quill setup so far:
export default class AddSpark extends Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.state ={
content: '',
};
}
onChange(html) {
this.setState ({ content: html });
console.log(html)
}
render() {
return (
<div>
<Col xs={12} md={6}>
<form ref={(input) => this.sparkForm = input} onSubmit={(e) => this.createSpark(e)}>
<ControlLabel>Select your city</ControlLabel>
<select id="formControlsCity" placeholder="Choose your city" onChange={this.onChange} className="form-control" onClick={ moreOptions } ref={(input) => this.city = input}>
<option value="select">Choose your city</option>
<option value="Beijing">Beijing</option>
<option value="Shanghai">Shanghai</option>
<option value="Chengdu & Chongqing">Chengdu & Chongqing</option>
</select>
<ControlLabel>Select your person</ControlLabel>
<select id="formControlsPerson" placeholder="Choose your person" className="form-control" ref={(input) => this.person = input}>
<option value="select">First select your city</option>
</select>
<ControlLabel>Select your location</ControlLabel>
<select id="formControlsLocation" placeholder="Choose your location" className="form-control" ref={(input) => this.location = input}>
<option value="select">First select your city</option>
</select>
<ControlLabel>Title</ControlLabel>
<input type="text" label="Title" placeholder="Enter your title" className="form-control" ref={(input) => this.title = input}/>
<ControlLabel>Content</ControlLabel>
<div className='_quill'>
<ReactQuill
ref='editor'
onChange={this.onChange}
/>
</div>
<br />
<Button type="submit">Submit</Button>
</form>
</Col>
<Col xs={12} md={6}>
<h3>Preview</h3>
{this.state.content}
</Col>
</div>
)}
}
At the moment I get this:
Any help is highly appreciated!
The simplest way is to use the same react-quill component with editing disabled. This method doesn't need you to install any extra package. You can do it by passing a prop readOnly whose value is set to true (By default it is false)
Here is the code for the component which you can use to preview side:
<ReactQuill
value={this.state.content}
readOnly={true}
theme={"bubble"}
/>
This is how it will look like:
Note: ReactQuill comes with two inbuilt themes (bubble and snow).
Here is how it looks in the snow theme. It has a toolbar at the top:
And here is how it looks in bubble theme.
You should use the "bubble" theme by passing the string "bubble" in the theme prop to display your editor content. This is because it does not have a toolbar at the top like the "snow" theme.
In order to use the bubble theme, you'll also have to import a CSS stylesheet for this specific theme as follow:*
import 'react-quill/dist/quill.bubble.css'
After doing some research I was able to find the answer:
To display the content of Quill in the preview section without the html tags I used this code:
<div dangerouslySetInnerHTML={{__html: this.state.content}}></div>
onChange(content, delta, source, editor) {
const text = editor.getText(content);
this.setState ({ content: text });
console.log(text)
}
You need html-react-parser
import Parser from 'html-react-parser';
... // in your render
<ReactQuill
...
value={code}
onChange={this.previewCode}
/>
...
{Parser(code)}
i used it like this in React.js..
To display quil content in a div i use class "ql-editor" because through this our div can use the quil default classes...works..
import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";
const ReactMarkdown = require("react-markdown/with-html"); //for displaying html
function editorContent() {
<div className="ql-editor" style={{ padding: 0 }}>
<ReactMarkdown escapeHtml={false} source={quilGeneratedHtml} />
</div>
}
Here's the docs link: https://github.com/zenoamaro/react-quill#the-unprivileged-editor
simple to implement and getText out of quill editor
// define function to get text,
// here inpText is defined in your constructor, or any global variable
onChangeText = () => {
const editor = this.reactQuillRef.getEditor();
const unprivilegedEditor = this.reactQuillRef.makeUnprivilegedEditor(editor);
// You may now use the unprivilegedEditor proxy methods
this.inpText = unprivilegedEditor.getText();
console.log("unprivilegedEditor.getText()", unprivilegedEditor.getText());
}
// on submit, you can set state with that text binded in this.inpText
this.setState({text: this.inputText})
}
// define react quill component
<ReactQuill value={this.state.text} onChange={this.onChangeText} ref={(el) => { this.reactQuillRef = el }} />
Good Luck...
Using 'html-react-parser' worked for me
Save the html output from quill editor. Then render it as an innerHTML on a div. Give class="ql-editor" to the div and the html will be formatted as we see it in the editor. No need to instantiate editor context. Just import quill's css file.
Vue example:
import '#vueup/vue-quill/dist/vue-quill.snow.css';
<div class="ql-editor" v-html="result"></div>
To preview HTML in your web page in REACT then there are 2 options you have,
using dependency html-react-parser
Follow below steps,
Step1:
Install dependency using below command,
npm i html-react-parser
If you are using yarn then use below command,
yarn add html-react-parser
Step 2:
const parse = require('html-react-parser');
parse(`<div>${this.state.content}</div>`);
Use below code to set the editor contents using below code,
<div
dangerouslySetInnerHTML={{
__html: this.state.content,
}}
I tried using 2 options:-
1> Using **dangerouslySetInnerHTML**, but this I will not recommend.
2> WE can try using a npm package for react such as
**html-react-parser**. Try it out, as its easy to use.

Categories

Resources