QuillJs strips span ids - quill

I am relatively new to coding and have been running into an issue with Quilljs that I don't know how to solve.
Use Case: I want to make a text editor that allows a user to write their notes but then be able to go back and annotate the text. Similar to google docs in the sense that people can add comments and remove comments if necessary. Annotation in my case is highlighting parts of their text and creating an insight from that. Everything works as designed. I am creating spans around the highlighted text and adding an id to each insight so that the user can remove them later if they don't think that was actually an insight from the text.
Problem: On reloading my text into quill value I notice that the first initial load has all of my id's correct but then quill runs an onChange event which updates the state and strips the ids from my text.
Question: How can I prevent Quilljs from stripping the span ids from my text? I looked in the docs and old questions but didn't think they were applicable to my question.
Tech: I am using react-quill fwiw
EDIT:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators, subscribe } from 'redux'
import ReactQuill, {Quill, Mixin, Toolbar } from 'react-quill';
import * as actionCreators from './quillTestActions'
class QuillTestContainer extends Component {
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
this.state = {
query: '',
text: '',
};
}
componentDidMount() {
this.setState({
text: this.props.Notes.selectedNote.props.text
})
}
handleChange(value){
this.setState({text: value})
}
_modules(){
return {
modules: {
toolbar: [
[{ 'header': [1,2,3,4,false]}],
['bold', 'italic', 'underline', 'strike', 'blockquote', 'code-block'],
[{'color': []}, {'background': []}],
[{'list': 'ordered'}, {'list': 'bullet'}, {'indent': '-1'}, {'indent': '+1'}],
['link', 'image'],
['clean']
],
}
}
}
render() {
return (
<ReactQuill
value = {this.state.text}
modules = {this._modules().modules}
onChange = {this.handleChange}
/>
)
}
}
function mapStateToProps (state) {
return {
Notes: state.Notes,
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actionCreators, dispatch)
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(QuillTestContainer)
Someone asked for code. This is a strip down essentials of the code that I am having a problem with. when I console out my value in the constructor or componentDidMount everything looks good but after the componentDidMount the onChange is initiated which strips the id's from my span class. For example, I might have something like <span id='test-id> that id is stripped out.

As part of optimization quill may remove the span tag. Did you try adding Span blot into your code (extend BlockEmbed)? Adding this will give you control on what node is created (inside create function of Spanblot). Please note that you will need to whitelist "span" so that this node is rendered inside the editor.

Related

How to sync when render a component?

i have a problem when i try catch new data went i change something in my content and render it.
import React, { Component } from 'react'
import { withNamespaces } from "react-i18next";
class Untitled extends Component {
constructor(props) {
this.columns = [...content]
}
render() {
const columns = this.columns.map((col) => {
return {
...col,
onCell: (record) => ({
record,
dataIndex: col.dataIndex,
title: col.title,
}),
};
});
return (
<div>
{columns}
</div>
)
}
}
export default Untitled
Here, when i change some values in [...content] i want "const columns" will update this new values and render it in return(). I am sure when [...content] update a new value had update in render(). But "const columns" still keep old value.
P/s: I cannot declare this.columns like this.state { columns: [] } because i don't want change code of old dev. Exactly i want get new value this.props.t("TEST") in this.columns when it toggle language.
Thanks you so much.
You can use this.forceUpdate() to manually trigger a re render
. You can get more explanation here https://reactjs.org/docs/react-component.html#forceupdate

Reactjs: Fade-in data not working properly

I have a button in App Component if i click in this button i get next item in array in the Component but the problem now the Fade-in Transition work only the fist item and not work's for the next item. how can i let Fade-in Transition work for next items?
My code:
import React, { Component } from 'react';
import FadeIn from 'react-fade-in';
class App extends Component {
constructor(props){
super(props);
this.state={indexTeam:0}
}
nextTeam=() => {
this.setState({ indexTeam: (this.state.indexTeam + 1) % teamList.length });
};
render() {
const teams = teamList[this.state.indexTeam];
return (
<div>
<FadeIn><h3>{teams.name}</h3></FadeIn>
<br/>
<button onClick={this.nextTeam}>Next Team</button>
</div>
);
}
}
const teamList = [
{
name: "1- Manchester United"
},
{
name: "2- Fc Barcelona"
},
{
name: "3- Inter Milan"
},
{
name: "4- Liverpool"
}
];
export default App;
Don't use that library. It does exactly that it should, fade in elements one by one when component (page in your case) mounts, but you need your transition on each rerender
If you will look through library that you are using (react-fade-in), you will notice that it reinits it's state on componentDidMount, so it doesn't work when you set state (so, just rerender it, not unmount and mount again).
I didn't come up with any fast solution how to fix or rewrite this library, so just think about yours.
Look through their realization (Which is simply based on css transition) and create your solution.
react-fade-in:
https://github.com/gkaemmer/react-fade-in/blob/master/src/FadeIn.js

how to open airbnb SingleDatePicker calendar on focus

Am trying to include a airbnb SingleDatePicker in my component as shown below
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
import { SingleDatePicker } from "react-dates";
export default class ExpenseForm extends React.Component {
constructor(props) {
super(props);
this.state = {
createdAt: moment(),
calendarFocused: false
};
this.onDateChange = this.onDateChange.bind(this);
this.onFocusChange = this.onFocusChange.bind(this);
}
onDateChange(createdAt) {
this.setState(() => ({ createdAt }));
}
onFocusChange({ focused }) {
this.setState(() => ({
focused
}));
}
render() {
return (
<div>
<SingleDatePicker
date={this.state.createdAt}
startDateId="MyDatePicker"
onDateChange={this.onDateChange}
focused={this.state.calendarFocused}
onFocusChange={this.onFocusChange}
id="SDP"
/>
</div>
);
}
}
It shows the current date inside the inside the input box as shown below but when i click on the field nothing happens(Calendar widget not opening).
Am not getting any errors in the console to figure out what is the issue. Could anyone please help me on fixing this issue?
It looks like you are targeting the wrong state key in your onFocusChange function. Try changing the function to this:
onFocusChange({ focused }) {
this.setState({ calendarFocused: focused });
}
Notice I also removed the anonymous function from inside of your setState call. You can remove it from your onDateChange function as well:
onDateChange(createdAt) {
this.setState(({ createdAt }));
}
I also noticed that you're using the startDateId prop that is not available for the SingleDatePicker. Airbnb uses that for the DateRangePicker to determine which input to focus on. There is only one input in the SingleDatePicker, so it does not require that prop. You can remove that prop without any change to your functionality.
1- correct this handler
onFocusChange = ({ focused }) => {
this.setState(() => ({ calendarFocused: focused }));
};
2- import 'react-dates/initialize'; //dependency as of v13.0.0
3-since u r not using webpack
Create a CSS file with the contents of require.resolve('react-dates/lib/css/_datepicker.css') and include it in your html section.
To see this in action, you can check out https://github.com/majapw/react-dates-demo which adds react-dates on top of a simple create-react-app setup.

HOC: A valid React element (or null) must be returned

I am trying to create HOC to wrap modals in, and am getting this error: A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
I have checked the few other threads, and the issues mainly seem to be imports - however I do not believe that is the case here. Here is my code:
create-modal.js
import { Component } from 'react'
import withRedux from 'next-redux-wrapper'
import Layout from '../../components/layouts/main'
import ModalContainer from './modal-container'
// Modal Layouts
import Empty from './empty'
import Basic from './basic'
const data = {
title: 'Silly Modal.',
layout: 'empty',
customClass: '',
multiStep: false,
steps: [
{
isVisible: true,
isAnimated: false,
animationName: null,
header: 'TEST',
currentContent: 'Testing the modal. What fun!',
buttons: {
closeText: 'Close',
closeAction: null,
continueText: null,
continueAction: null,
},
closeRedirect: null,
closeRedirectPath: null,
continueRedirect: null,
continueRedirectPath: null,
},
],
}
function newModal (WrappedComponent, data) {
if (!WrappedComponent && !data) return null
return class Modal extends Component {
constructor (props) {
super(props)
}
render () {
return (
<Layout>
<ModalContainer>
<WrappedComponent />
</ModalContainer>
</Layout>
)
}
}
}
console.log('what is newModal returning?!', (newModal(<Basic />, data)) )
export default newModal
console.logging the return of calling this HOC shows that it is returning a function rather than a component:
function Modal(props) {
(0, _classCallCheck3.default)(this, Modal);
return (0, _possibleConstructorReturn3.default)(this, (Modal.__proto__ || (0, _getPrototypeOf2.default)(Modal)).call(this, props…
Which seems wrong.
I should also note that I may be doing this return wrong (but am not sure. I have tried return <WrappedComponent /> with the same result however :(
All of the components I am importing are exported as default so not using the brackets on the import is, I believe, correct here. I am new to HOC's and am just not seeing what is wrong, as I am following the patterns I see for them closely. Any help is appreciated!
You are returning the class constructor with this statement:
return class Modal extends Component {
which is why it's complaining
You could probably just use a pure React component, as you appear not to be needing props or state.
That will get you past this problem, but I suspect you need to do it differently anyway, because it looks like you want to pass in an element, and render that element inside a modal wrapper.
Look up how to use {this.props.children} for a clue, or if I'm on the right track I can help you more.
UPDATE
I think what you want to do is take advantage of children. You can do something like this:
<ModalWrapper name="A modal dialog (which is generic and re-usable)">
<SomethingElse name="This is my custom component">
:
:
</SomethingElse>
</ModalWrapper>
In the render method of ModalWrapper you just render {this.props.children} and it brings in whatever markup you have as children.
(I am not 100% sure if it's {this.props.children}, but you'll get my drift
An HOC is a function that receives a Component, wraps it to add more functionality and return another component. It is not that you can use it as a Component in your code. You use it to enhance an existing Component.
You are not using the HOC component correctly, you should do it like this:
import Basic from './basic'
...
const NewModal = newModal(Basic, data)
...
render()
<NewModal ... />
Look at the official react documentation for an example:
https://reactjs.org/docs/higher-order-components.html

Pass Data to React Component dynamically

I am currently developing a custom component in ReactJS that is able to display a tree based on a JSON:
export default {
name: 'Main Node', nodeid: 99,toggled: true,
children: [
{ name: 'Secondary Node',nodeid: 0,
chosen: false,pushed: false,toggled: false,
children: [
{ name: 'Leaf Node',nodeid: 1,chosen: false,
pushed: false, toggled: false,
children: [{
name : "child 1", pushed: false,
toggled: false, chosen:false
}]
}
]
}
]
};
Currently, the component is able to render itself because I am sending the JSON from a static Data.js file as shown below:
import React from 'react';
import TreeComponent from 'reusable-components/TreeComponent';
import HierarchyJson from './internal/Data';
export default function ExampleTreeComponent() {
return <TreeComponent hierarchyJson={HierarchyJson} functionMode={4} htmlId="tree1"
pushLabelValue="include SubLevel"
unpushAlertText="plz choose something"
pushAlertText="plz choose something" />
}
What I want to achieve is to have the same functionality within my web pages, but receiving the JSON data from an HTTP call.
I am a beginner in ReactJS, so I'm lost at the moment.
Your tree component does not need to worry about where the data is coming from, rather it s only worried that there is data. In other words, whether you get the data from some local file or from an ajax request to an api should not be the concern of the tree component. All you need to to is make sure that the data that it requires gets sent down to it. Here is an example of what I mean.
class sample extends React.Component {
constructor() {
this.state = {
myData: {} //this is the tree
}
}
componentDidMount() {
ajax.request(some end point).then(data => {
this.setState({myData: data});
})
//this is where its recomended to make async calls. When the promise resolves
//the component will render again due to setState being called
//and this time myData will be your data from the api
//and now the tree component has what it needs to render the data
}
render() {
<Tree data={myData} /> //
}
}

Resources