I'm a newbie with ReactJS and I'm doing a project with ReactJS ES6. In my project, I use Froala Editor, it works perfectly. But now, I have a new feature requires Froala Editor adding input text, text area so Froala need more configuration. I don't know where to place configuration in ReactJS component. Here is my React component.
import FroalaEditor from 'react-froala-wysiwyg'
import FroalaEditorView from 'react-froala-wysiwyg/FroalaEditorView'
class RequestFormComponent extends Component {
constructor(props) {
super(props);
this.handleModelChange = this.handleModelChange.bind(this);
$.FroalaEditor.DefineIcon('insertInputField', {NAME: 'plus'});
$.FroalaEditor.RegisterCommand('insertInputField', {
title: 'Insert InputField',
focus: true,
undo: true,
refreshAfterCallback: true,
callback: function () {
this.html.insert(some input text);
}
});
this.state = this._getState();
}
_getState() {
return {
content: "Some text",
config: {
toolbarButtons: ['undo', 'redo', 'clearFormatting', 'selectAll', 'html', 'insertInputField']
}
}
}
handleModelChange(model) {
this.setState({content: model});
}
render() {
return (
<FroalaEditor
model={this.state.content}
onModelChange={this.handleModelChange}
config = {this.state.config}
/>
)
}
If I config like this, console will show error message "Cannot read property 'DefineIcon' of undefined"
I researched a lot but got nothing.
Please give me some advices to fix this issue.
I think you should import jquery:
import $ from 'jquery';
You have to import jQuery.
import $ from 'jquery';
Install jQuery by npm i jquery -s command.
And have to trigger the jQuery in componentDidMount method.
componentDidMount() {
$.FroalaEditor.DefineIcon('insertInputField', {NAME: 'plus'});
$.FroalaEditor.RegisterCommand('insertInputField', {
title: 'Insert InputField',
focus: true,
undo: true,
refreshAfterCallback: true,
callback: function () {
this.html.insert(some input text);
}
});
this.state = this._getState();
}
Related
After installing vue3-select2-component with their document when i implementing that. it doesn't show in output on html but i have the html of that in source code
BTW: i'm using inertiajs on Laravel framework
install:
// npm install
npm install vue3-select2-component --save
Use as component:
import {createApp, h} from 'vue'
import BootstrapVue3 from 'bootstrap-vue-3'
import IconsPlugin from 'bootstrap-vue-3'
import {InertiaProgress} from "#inertiajs/progress";
import {createInertiaApp, Head} from '#inertiajs/inertia-vue3'
import {Link} from "#inertiajs/inertia-vue3"
///...
import Select2 from 'vue3-select2-component';
import {createStore} from "vuex"
///...
createInertiaApp({
resolve: async name => {
return (await import(`./pages/${name}`)).default;
},
setup({el, App, props, plugin}) {
createApp({render: () => h(App, props)})
.use(plugin)
.use(bootstrap)
.use(BootstrapVue3)
.use(IconsPlugin)
.use(VueSweetalert2)
.component('Link', Link)
.component('Select2', Select2)
.mount(el)
},
title: title => 'azizam - ' + title
}).then(r => {
});
vuejs page which i want to use into that:
<template>
<Select2 v-model="myValue" :options="myOptions"
:settings="{ settingOption: value, settingOption: value }"
#change="myChangeEvent($event)"
#select="mySelectEvent($event)" />
</template>
<script>
import menubar from "./menubar";
import emulator from "./emulator";
import {mapActions} from "vuex";
import notification from "../../../partials/notification";
export default {
name: "image",
data() {
return {
caption: '',
myValue: '',
myOptions: ['op1', 'op2', 'op3']
}
},
components: {
menubar,
emulator,
notification
},
methods: {
...mapActions([
'changeBreadcrumb'
]),
myChangeEvent(val){
console.log(val);
},
mySelectEvent({id, text}){
console.log({id, text})
}
},
mounted() {
const payload = {
title: 'محصولات',
subTitle: 'ایجاد محصول تک عکس در سامانه'
};
this.changeBreadcrumb(payload);
}
}
</script>
console log:
Warning - slinky.min.js is not loaded. application.js:336:21
[Vue warn]: A plugin must either be a function or an object with an "install" function. vendor.js:10544:17
[Vue warn]: Plugin has already been applied to target app. vendor.js:10544:17
Use of Mutation Events is deprecated. Use MutationObserver instead. content.js:19:11
Source map error: Error: request failed with status 404
Resource URL: http://127.0.0.1:8000/js/vendor.js?id=594b688c9609a79fb52afd907a69c736
Source Map URL: tooltip.js.map
in console as you can see i don't get any error for this component
html source code:
<select2 options="op1,op2,op3" settings="[object Object]"></select2>
and then webpack:
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js')
//.sass('resources/scss/app.scss','public/css')
.extract()
.vue({
version: 3,
options: {
compilerOptions: {
isCustomElement: (tag) => ['Select2'].includes(tag),
},
},
})
.postCss('resources/css/app.css', 'public/css', [
//
])
.version();
The problem is you've configured Vue to treat <Select2> as a custom element, so the actual component does not get rendered.
The fix is to remove that configuration:
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js')
//.sass('resources/scss/app.scss','public/css')
.extract()
.vue({
version: 3,
//options: {
// compilerOptions: {
// isCustomElement: (tag) => ['Select2'].includes(tag), ❌ remove this
// },
//},
})
.postCss('resources/css/app.css', 'public/css', [
//
])
.version();
I am developing a react app which uses Editor.js as an editor and that page is working fine. But when ever i try to access other pages it gives Unhandled Rejection. This is confusing because i am importing editorjs packages only to the editor page, but it's asking for element with id "element-js".
This is editor connfig file.
const editor = new EditorJS({
holder: 'editorjs',
autofocus: true,
tools: {
paragraph: {
class: Paragraph,
inlineToolbar: true,
config: {
placeholder: 'Write Here....'
},
},
table: {
class: Table,
inlineToolbar: true,
config: {
rows: 2,
cols: 3,
},
},
header: {
class: Header,
/**
* This property will override the common settings
* That means that this tool will have only Marker and Link inline tools
* If 'true', the common settings will be used.
* If 'false' or omitted, the Inline Toolbar wont be shown
*/
inlineToolbar: true,
config: {
placeholder: 'Header'
},
shortcut: 'CMD+SHIFT+H'
},
delimiter: Delimiter,
warning: Warning,
list: {
class: List,
inlineToolbar: [
'link',
'bold'
]
},
quote: Quote,
checklist: {
class: Checklist,
inlineToolbar: true,
},
Marker: {
class: Marker,
shortcut: 'CMD+SHIFT+M',
},
embed: {
class: Embed,
inlineToolbar: false,
config: {
services: {
youtube: true,
coub: true
},
},
},
image: ImageTool,
}
});
And how i am importing:
import EditorJS from '#editorjs/editorjs';
import Header from '#editorjs/header';
import List from '#editorjs/list';
import Checklist from '#editorjs/checklist';
import Embed from '#editorjs/embed';
import Marker from '#editorjs/marker';
import Warning from '#editorjs/warning';
import Quote from '#editorjs/quote';
import Delimiter from '#editorjs/delimiter';
import ImageTool from '#editorjs/image';
import Table from "#editorjs/table";
import Paragraph from "#editorjs/paragraph";
I don't know what's the problem here. In my opinion these imports are importing globally to the whole app.
I know this is a bit late but some other people like me still arrive here with the same issue and some of us don't want to use an unofficial editor.js component.
So the issue is pretty simple, that error means that you must have an element with id editorjs in the DOM but since Im using Next.js I will explain how to use it step by step. (you won't need extra steps if you are only using React)
Create a component that looks like this: (You have to install plugins otherwise you will get some errors)
import Embed from '#editorjs/embed'
import Table from '#editorjs/table'
import List from '#editorjs/list'
import Warning from '#editorjs/warning'
import Code from '#editorjs/code'
import LinkTool from '#editorjs/link'
import Image from '#editorjs/image'
import Raw from '#editorjs/raw'
import Header from '#editorjs/header'
import Quote from '#editorjs/quote'
import Marker from '#editorjs/marker'
import CheckList from '#editorjs/checklist'
import Delimiter from '#editorjs/delimiter'
import InlineCode from '#editorjs/inline-code'
import SimpleImage from '#editorjs/simple-image'
import EditorJS from '#editorjs/editorjs'
const EditorNoSSR = ({ type }) => {
const TOOLS = {
embed: Embed,
table: Table,
marker: Marker,
list: List,
warning: Warning,
code: Code,
linkTool: LinkTool,
image: Image,
raw: Raw,
header: Header,
quote: Quote,
checklist: CheckList,
delimiter: Delimiter,
inlineCode: InlineCode,
simpleImage: SimpleImage,
}
const editor = new EditorJS({
/**
* Id of Element that should contain the Editor
*/
holder: 'editorjs',
tools: TOOLS,
})
return (<>
<div>
<div id="editorjs">
</div>
</div>
</>);
}
export default EditorNoSSR;
That is a component that you will import using next/dynamic and it will work perfectly. And to share data from this component to another you can use react's context.
Now a page where you call the component will look like this:
import { useState, useEffect } from "react";
import dynamic from "next/dynamic";
const EditorNoSSR = dynamic(() => import("../../../components/EditorNoSSR"), { ssr: false })
const EditorPage = () => {
return (<>
<EditorNoSSR />
</>);
}
export default EditorPage;
Now I have used React-editor-js and it's working fine.
https://www.npmjs.com/package/react-editor-js
I have just started using Storybook for a UI component lib I am working on. I wanted to extract JSDoc written for JS class methods and properties into Storybook and create a Doc.
Storybook does support creating doc for React components by reading its propTypes. Is there addon or someway to do the same for a JS class.
I am using the latest storybook 6.
Thanks in advance
You can do it like a normal component:
form-validators.stories.ts
import { FormValidators } from './path';
export default {
title: 'Components/Form Validators',
component: FormValidators,
parameters: {
previewTabs: { canvas: { hidden: true } },
docsOnly: true,
},
} as Meta;
export const Default: Story = () => ({
template: '<div>Test</div>',
});
Or I prefer an MDX file.
form-validators.stories.mdx
import { ArgsTable } from '#storybook/addon-docs/blocks';
import { Meta } from '#storybook/addon-docs/blocks';
import { FormValidators } from './path';
<Meta
title="Components/Form Validators"
parameters={{ previewTabs: { canvas: { hidden: true } } }}
/>
<ArgsTable of={FormValidators} />
I am using react-codemirror and want to highlight the text 'Hello' in the Codemirror but the match-highlighter addon is not highlighting the same. Below is the code for the same.
import React, { Component } from 'react';
import { render } from 'react-dom';
import CodeMirror from 'react-codemirror';
import 'codemirror/lib/codemirror.css';
import 'codemirror/addon/search/match-highlighter';
import 'codemirror/mode/javascript/javascript';
class App extends Component {
constructor() {
super();
this.state = {
name: 'CodeMirror',
code: '//Test Codemirror'
};
}
updateCode(newCode) {
this.setState({
code: newCode,
});
}
render() {
let options = {
lineNumbers: true,
mode: 'javascript',
highlightSelectionMatches: {
minChars: 2,
showToken: /Hello/,
style:'matchhighlight'
},
styleActiveLine: true,
styleActiveSelected: true,
};
return (
<div>
<CodeMirror value={this.state.code} onChange={this.updateCode.bind(this)} options={options}/>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Current output is in the screenshot below and the word is not highlighted.
I found a solution for this issue. Inorder to enable the highlighting one need to add a css corresponding to the style property. I added the below code in css file and it started working
.cm-matchhighlight {
background: red !important
}
Now it highlights the token properly
I'm working on an app I'm migrate to VueJS so some parts are using old jQuery code.
So I'm trying to append an VueJS component using jQuery, so I made
import copyToClipboard from '../components/_base/VCopyToClipboard';
const CopyToClipboard = Vue.extend(copyToClipboard);
$(event.currentTarget).find('.dns-challenge-row').each((index, element) => {
const component = new CopyToClipboard({
propsData: {
targetId: $(element).find('code').attr('id'),
},
}).$mount();
$(element).append(component.$el);
});
Everything is working BUT when I go on the page where this component is appended, i18n return an error
Cannot translate the value of keypath 'tooltip.default'. Use the value of keypath as default.
FYI my translation messages are directly defined inside my SFC using the i18n keyword
i18n: {
messages: {
en: {
tooltip: {
default: 'Copy content',
success: 'Copied',
},
},
fr: {
tooltip: {
default: 'Copier le contenu',
success: 'Copié',
},
},
},
},
and I use then directly inside the SFC using this.$t('tooltip.default')
My i18n is import like the docs say but is loaded after the vue.js I use to create my component.
import {
Vue,
} from './vue';
import VueI18n from 'vue-i18n';
import en from '../../translations/en';
import fr from '../../translations/fr';
Vue.use(VueI18n);
export default new VueI18n({
locale: document.getElementsByTagName('html')[0].getAttribute('lang'),
messages: {
en,
fr,
},
});
The vue.js file is the the file where I put all my Vue.use() definitions, my routern, other stuff and is used to create the Vue instance inside another file
vueSetup(new Vue({
el: '#app',
components: {
...
},
i18n: i18n,
router: router,
store: store,
}));
Do you have an idea to solve this?
I tried to load i18n before the vue component without success and I saw a lot of GitHub issues with this error but not like my case.
Just import and add i18n instance to the new component instance
const CopyToClipboard = Vue.extend(copyToClipboard);
$(event.currentTarget).find('.dns-challenge-row').each((index, element) => {
const component = new CopyToClipboard({
i18n: i18n,
propsData: {
targetId: $(element).find('code').attr('id'),
},
}).$mount();
$(element).append(component.$el);
});