I have some issues with dynamic import of the component in my NextJs app. I'm trying to import Froala text editor and it's supported for React. But, when I try to import it, I have errors that window is not defined, so I'm importing it with next/dynamic.
So the problem is, this editor should not reload on every change on page. Whatever I do, ex. change state, it will rerender the component. It's only blinking, but still cannot show like so to the client. Is there any other way I could use component and not "blink"?
Here is my component:
import FroalaEditor from 'react-froala-wysiwyg';
const Froala = (props: {model: any, onChanged: any}) => {
return (
<div>
<FroalaEditor model={props.model} onModelChange={props.onChanged} config={{
toolbarButtons: ['fullscreen', 'bold', 'italic', 'textColor', 'backgroundColor', 'underline', 'strikeThrough', 'fontFamily', 'fontSize', 'color', 'inlineClass', 'inlineStyle', 'paragraphStyle', 'paragraphFormat', 'align', 'formatOL', 'formatUL', 'outdent', 'indent', 'quote', 'insertLink', 'insertImage', 'insertVideo', 'embedly', 'insertFile', 'insertTable', 'emoticons', 'fontAwesome', 'specialCharacters', 'insertHR', 'selectAll', 'clearFormatting', 'print', 'getPDF', 'spellChecker', 'help', 'html', 'undo', 'redo'],
toolbarButtonsXS: ['bold', 'italic', 'fontFamily', 'fontSize', 'undo', 'redo'],
placeholderText: 'Edit Your Content Here!',
charCounterCount: false,
theme: 'dark',
imageUploadParam: 'image_param',
fileUploadMethod: 'POST',
fileUploadURL: 'http://127.0.0.1:8000/upload_file',
// Set the image upload URL.
imageUploadMethod: 'POST',
imageUploadURL: 'http://127.0.0.1:8000/api/upload/image',
// Set request type.
// Set max image size to 5MB.
imageMaxSize: 5 * 1024 * 1024,
// Allow to upload PNG and JPG.
imageAllowedTypes: ['jpeg', 'jpg', 'png'],
}}/>
</div>
)
}
export default Froala
And importing to other components would be:
const FroalaEditor = dynamic(() => import('../Froala'), {
ssr: false
});
It's not important what I change on the page... dispatch, state, or whatever that can cause rerendering, it will blink. How can I prevent this?
Btw, if component is directly imported, it's giving an error of undefined window!
Related
I use draftJS to edit text in my project, and at the moment I'm faced with such a problem that if you include a list with dots or numbers in an empty editor, then it cannot be deleted with the backspace key
my editor
```<Editor
editorState={description}
toolbarStyle={editorStyles.toolbarStyle}
editorStyle={editorStyles.editorStyle}
onEditorStateChange={onChangeDescription}
placeholder={placeholder}
toolbar={toolbar}
/>```
I just study draft.js. you can handle the key command by RichUtils.handleKeyCommand.
The code below is that i create a function handleKeyCommandEn.then it can handle backspace to remove list
import { EditorState, convertToRaw, ContentState,RichUtils } from "draft-js";
...
const [editorStateEn, setEditorStateEn] = useState<EditorState>(EditorState.createEmpty());
const handleKeyCommandEn = (command) => {
const newState = RichUtils.handleKeyCommand(editorStateEn, command);
if (newState) {
setEditorStateEn(newState);
return true;
}
return false;
};
...
<Editor
editorState={editorStateEn}
wrapperClassName="demo-wrapper"
editorClassName="demo-editor"
onEditorStateChange={setEditorStateEn}
toolbar={{
options:['inline','blockType', 'fontSize', 'fontFamily', 'list', 'textAlign', 'remove', 'history'],
textAlign: { inDropdown: true },
inline :{options:['bold', 'italic', 'underline', 'strikethrough','superscript','subscript']}
}}
localization={{
locale: 'en',
}}
stripPastedStyles={true} // disable paste style
handleKeyCommand={handleKeyCommandEn}
placeholder={intl.formatMessage({ id: "editorPlaceholder" })}
/>
I am using Laravel 8 and InertiaJS (Vue js)
I am using the html2pdf.js to generate PDF. So I create a component for that : ExportPdf.vue
So here is the code of the component ExportPdf.vue :
<template>
<div>
<button class="px-6 py-3 rounded bg-gray-600 hover:bg-gray-900 text-white text-sm font-bold whitespace-no-wrap"
#click="exportToPDF">Expot to PDF
</button>
</div>
</template>
<script>
import html2pdf from 'html2pdf.js'
export default {
props:{
area: HTMLDivElement,
name : String,
orientation : {
type: String,
default(){
return 'landscape'
}
}
},
methods:{
exportToPDF () {
html2pdf(this.area, {
margin: [1.5, 1],
filename: this.name + '.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {scale: 2},
jsPDF: { unit: 'cm', format: 'a4', orientation: this.orientation , floatPrecision: 16 }
})
}
}
}
</script>
And then I'm using this component inside any component which I want to extract the content into PDF file like this :
<export-pdf name="file name" :area="$refs.content" />
AND I reference to Div I want to extract using ref like :
<div ref="content">
<!-- Content to Extrat into PDF -->
</div>
The first time It WORKS but when I change a component (I go to another vue), It doesn't work, So I must refresh the page.
I console log the prop (this.area which receive the $refs.content from the parent) inside the ExportPdr component => it's undefined.
I think that is because this component is mounted before the $refs.content is initialised in the parent (If I can say that)
I found a solution but In my opinion It is not perfect. Because I need to add v-if to ExportPdf component in Each Parent Component and make the boolean to true in the mounted method of the parent. This fixed the problem and the prop is not Undefined anymore. That is all to make it works without refreshing the page every time. BUT it's tedious to add these lines every time to each parent component.
like this :
Parent template :
<export-pdf v-if="isMounted" name="Liste des consommables des équipements" :area="$refs.content" />
data(){
return {
isMounted : false,
}
},
mounted(){
this.isMounted = true
}
So Any suggestoin to make it better ?
Thanks.
Because
The child component is mounted before parent.
$refs is not reactivity,you should avoid accessing $refs from within templates or computed properties.
Solution 1:
<div ref="content">
<!-- Content to Extrat into PDF -->
</div>
<export-pdf name="Liste des consommables des équipements" :area="refElement" />
<script>
export default {
data(){
return {
refElement: {},
}
},
mounted(){
this.refElement = this.$refs.content
}
}
</script>
Solution 2:
parent:
<div ref="content">
<!-- Content to Extrat into PDF -->
</div>
<export-pdf name="Liste des consommables des équipements" areaRefName="content" />
children:
props:{
areaRefName: String,
name : String,
orientation : {
type: String,
default(){
return 'landscape'
}
}
},
methods:{
exportToPDF () {
let element = this.$parent.$refs[this.areaRefName]
html2pdf(element , {
margin: [1.5, 1],
filename: this.name + '.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {scale: 2},
jsPDF: { unit: 'cm', format: 'a4', orientation: this.orientation , floatPrecision: 16 }
})
}
}
I am using react-quill and I wan't to know how to select an image after being inserted into the editor and how to get the delted image url after being delted.
Here is my Editor Component
import React,{useState} from 'react'
import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';
const modules = {
toolbar:{
container: [
[{ 'header': [1, 2, false] }],
['bold', 'italic', 'underline','strike', 'blockquote'],
[{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
['link', 'image'],
['clean']
],
handlers:{
'image': async function(){
const editor=this.quill
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*');
input.click();
input.addEventListener('change',(e)=>{
const url=awiat uploadFile(e.target.files[0))
const range = editor.getSelection(true);
editor.insertEmbed(range.index, 'image', url;
editor.setSelection(range.index + 1)
})
}
}
}
}
const formats = [
'header', 'font', 'size',
'bold', 'italic', 'underline', 'strike', 'blockquote',
'list', 'bullet', 'indent',
'link', 'image', 'color',
]
function Editor() {
const [editorData,setEditorData]=useState(" ")
const handleChange=(value)=>{
setEditorData(value)
}
return (
<div>
<ReactQuill formats={formats} modules={modules} value={editorData}
onChange={(data)=>handleChange(data)} />
</div>
)
}
export default Editor
So, how can i select a image inside the editor after being inserted and get the url after being deleted from the editor.
First, you should store your uploaded image URL inside an array like:
const [addresses, setAddresses] = useState([])
addresses.push(url)
Then when you submit the form, check if these addresses exist in your editor content save them, else any of them not exists delete it.
addresses.map(async (a) => {
if (!yourEditorValue.includes(a)) {
/* here you can add your method according to your backend, I am
using strapi */
const deletePhoto = await axios.delete(
`${yourServerUrl}/upload/files/${id}`,
{
//this one is not necessary if you don't need
headers: {
Authorization: `Bearer ${yourToken}`,
},
},
)
}
return true
})
CKEditor image upload is not working and below is the code
<CKEditor
editor={ ClassicEditor }
data={this.state.miscNotesData.miscnote}
onInit={ 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();
this.handleChange(data);
console.log( { event, editor, data } );
} }
/>
Error:
backend.js:6 filerepository-no-upload-adapter: Upload adapter is not defined.
Read more: https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html#error-filerepository-no-upload-adapter
As provided in documentation https://ckeditor.com/docs/ckeditor5/latest/features/image-upload/image-upload.html
there are 4 options to upload images in CKEDitor: Easy Image(proprietary), CKFinder(needs connector on PHP or ASP.net), Simple adapter, Base64 adapter
I use Simple adapter for this purpose with Node js server:
First, I installed SimpleUploadAdapter in ClassicEditor, then I set up config in CKEditor:
<CKEditor
data={input.value}
editor={ ClassicEditor }
config={{
simpleUpload: {
uploadUrl: 'https://myserver.herokuapp.com/image-upload'
},
toolbar: ['heading', '|', 'bold', 'italic', 'blockQuote', 'link', 'numberedList', 'bulletedList', 'imageUpload', 'insertTable',
'tableColumn', 'tableRow', 'mergeTableCells', 'mediaEmbed', '|', 'undo', 'redo']
}}
/>
And create url on my server /image-upload
I'm using CKeditor5 document editor in reactjs. And i want to make it disabled or readonly. I'm sending parameter in config but not working.
<CKEditor2
editor={DecoupledEditor}
data="<p>Hello from CKEditor 5!</p>"
onInit={editor => {
editor.ui.view.editable.element.parentElement.insertBefore(
editor.ui.view.toolbar.element,
editor.ui.view.editable.element
);
}}
config={
{
toolbar: ['bold', 'italic', 'bulletedList', '|', 'numberedList', 'alignment'],
removePlugins: ['Heading', 'Link'],
isReadOnly: true,
}
}
/>
Ok I think I found out what you're looking for:
Here you have a description of the component properties. On the last one you can see "disabled"
So you're code would look something like this:
<CKEditor2
editor={DecoupledEditor}
data="<p>Hello from CKEditor 5!</p>"
disabled=true
onInit={editor => {
editor.ui.view.editable.element.parentElement.insertBefore(
editor.ui.view.toolbar.element,
editor.ui.view.editable.element
);
}}
config={
{
toolbar: ['bold', 'italic', 'bulletedList', '|', 'numberedList', 'alignment'],
removePlugins: ['Heading', 'Link'],
isReadOnly: true,
}
}
/>
Also, I think you probably meant <CKEditor instead of <CKEditor2.
Use editor.enableReadOnlyMode("editor"); Docs
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.ckeditor.com/ckeditor5/35.0.1/classic/ckeditor.js"></script>
</head>
<body>
<div id="editor">Test</div>
<script>
ClassicEditor.create(document.querySelector("#editor"), {
toolbar: [],
}).then(editor => {
editor.enableReadOnlyMode("editor");
console.log(editor);
}).catch(error => {
console.error(error);
});
</script>
</body>
</html>