Getting values from a text editor in React js - javascript

I'm using a quill js component (a text editor) for Reactjs and I'm testing it to see all it's features.
I managed to build a editor with a toolbar, but now I have a doubt, how can I get everything the user typed and save it in my state? As I'll show you in the code if I console.log(the quillRef.current) I get a div and way inside it I have a p element which contains everything the user has typed. My idea is to place a button in the end, and when the user stops typing and clicks the button I store what they typed.
here's a link to the sandbox where I'm testing it:
codesandbox link

With quill.getText() function :
import React, { useState } from "react";
import { useQuill } from "react-quilljs";
export default () => {
const { quill, quillRef } = useQuill();
const [savedText, setSavedText] = useState("");
const handleSave = () => {
const text = quill.getText();
setSavedText(text);
};
return (
<div style={{ width: 500, height: 300 }}>
<button onClick={handleSave}>SAVE</button>
<div>Saved State : {savedText}</div>
<div ref={quillRef} />
</div>
);
};
Check on codesandbox : https://codesandbox.io/s/react-quilljsbasic-tt6pm?file=/src/App.js

Related

Dynamic import module and css-modules(React, Next.js)

I want to understand the work of css-modules + dynamic modules. I have a global Button component that is used throughout the application. There is also some form (a modal window with a form) that uses a Button and is imported into the application via dynamic modules. The problem is that when the form opens, i.e. a dynamic module is loaded onto the page, the styles of this dynamic component get to the very bottom of the page, which leads to a repeated redefinition of css.
Code Examples:
// button.module
.button {
margin: 0;
}
// Button.js
import React from 'react';
import styles from './button.module.css';
// using styles
export function Button({ className = '', onClick = () => {} }) {
return (
<button
className={`${styles.button} ${className}`}
onClick={onClick}
>
Button text
</button>
)
}
Dynamic component:
// form.module.css
.form__button
{
margin: 10px 0 0;
}
// Form.js component
import React from 'react';
import styles from './form.module.css';
export function Form() {
return (
<>
...
<Button className={styles.form__button}/>
...
</>
)
}
Client code:
// page.module.css
.page__button {
margin: 20px 0;
}
// Client code
import React from 'react';
import styles from './page.module.css';
import dynamic from "next/dynamic";
// Dynamic form component
const Form = dynamic(() =>
import("#/compoents/Form").then((mod) => mod.Form)
);
export function Page() {
const [show, setShow] = useState(false);
return (
<>
...
{show ? <Form /> : null}
// before show form margin for button '20px 0'
<Button
className={styles.page__button}
onClick={() => setShow(true)}
/>
// after show form margin for button '10px 0 0'
</>
);
}
In this case, the problem will be that when the Form component is loaded, the styles for the Button will also be loaded down and will override our styles.form__button styles. The only solution I see is to use a local Button component, which will actually be used only for this component and contain minimal styles, layout. But this option seems to me not quite correct. I will be glad of any help

How to change displayed text in react component?

I installed react-mailchimp-subscribe and I want to change text button because my website is not written in English.
i putted this component into div className="pokemon" to have access to him like .pokemon > div > button and could have change styles. Now I want to change text.
I try to acces to him by using
useEffect(() = > {
document.addEventListener("load", function(){
(".pokemon>div>button").innerHtml("Wyślij")
}); }, [])
but I guess in my function is too many errors that it actually work.
You can update the button label using the state. Please refer the below code
import React, { useEffect, useState } from 'react'
export default function App() {
const [buttonLabel, setButtonLabel ] = useState("I'm Button");
useEffect(() => {
setButtonLabel("Wyślij")
}, [])
return (
<div className="pokemon">
<div>
<button> {buttonLabel}</button>
</div>
</div>
)
}
Here is the link to codesandbox environment
If you want to do it using dom, you can use the below code.
You have some minor syntax mistake.
useEffect(() = > {
document.addEventListener("load", function(){
document.querySelector(".pokemon").querySelector("div").querySelector("button").innerHTML = "Wyślij";
}); }, [])

Highlight value of #material-ui/core TextField in React at specific indices

I am working on React and I have created a form using TextField from #material-ui/core. The user will enter the text, it will pass
to a server in the backend, and a new text will appear. I can easily do this by changing the value of the TextField.
My problem is, when I show the output in the TextField, I want some of the strings to be highlighted as shown in the figures.
Before
After
I can get the indices and the tokens from the backend, but I didn't find a way to highlight parts of the TextField value.
All what I found is styling the whole value using InputProps. I have tried using this answer, and react-highlight-words package, but I can't set the value using those as it will return an object and the shown value will be [object object] rather than a partially highlighted string
I also tried find-substring-in-text-and-change-style-programmatically
and uses TextField rather than Text, but I want only one TextField, not a different TextField for each word. I have added what I did
based on this answer in my code.
Here is a simplified version of my code
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();`
app.js
import React, { Component } from 'react';
import './App.css';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import HomePage from './HomePage';
import 'bootstrap/dist/css/bootstrap.css';
class App extends Component {
render() {
return (
<div className="App">
<>
<Router>
<Switch>
<Route path='/' exact component={HomePage} />
</Switch>
</Router>
</>
</div>
);
}
}
export default App;
HomePage.js
import React from 'react'
import { TextField, Button } from "#material-ui/core";
const HomePage = () => {
const [value, setValue] = React.useState();
const [indices, setIndices] = React.useState();
const [substrings, setSubstrings] = React.useState();
const handleChange = (event) => {
setValue(event.target.value)
}
const handleChange2 = (event) => {
// What to set?
}
const handleClear = () => {
setValue("")
}
const handleSubmit = () => {
let axios = require('axios')
let data = {
"text": value
}
axios.post('http://127.0.0.1:8000/predict', data)
.then(response => (setValue(response.data.value),
setIndices(response.data.indices),
setSubstrings(response.data.substrings)
))
}
return (
<form noValidate autoComplete="off">
{/*This is the block that I tried from this link https://stackoverflow.com/questions/57808195/react-native-find-substring-in-text-and-change-style-programmatically*/}
{/*
{['red','black','green'].map(item => (
<TextField
InputProps={{
style: {
background: item,
},
}}
value={item}
onChange={handleChange2}
/>
))}
*/}
<TextField
value={value}
rowsMax={15}
InputProps={{
style: {
fontWeight: 500,
},
}}
variant="outlined"
onChange={handleChange}
/>
<Button onClick={handleClear}>Clear</Button>
<Button onClick={handleSubmit}>Submit</Button>
</form>
);
};
export default HomePage;
Is there a way to do this? or a simpler approach like passing an HTML code to the value?
UPDATE:
I solved the problem using native contentEditable native as Julien Ripet suggests. Here is the updataed HomePage.js code.
import React from 'react'
import {Button } from "#material-ui/core";
const HomePage = () => {
// This handler will listen to the paste event. It will serves as "paste as plain text" to avoid pasting the style.
const handlePaste = (event) => {
// cancel paste
event.preventDefault();
// get text representation of clipboard
var text = (event.originalEvent || event).clipboardData.getData('text/plain');
// insert text manually
document.execCommand("insertText", false, text);
}
// Set the textbox to empty when the clear button is clicked
const handleClear = () => {
var inputText = document.getElementById("textbox");
inputText.innerHTML = "";
}
// Send the text to the server, pass the returned value with its indices to the highlight function to be highlighted and rendered on the same box
const handleSubmit = () => {
// Get the object of the textbox
var inputText = document.getElementById("textbox");
// use innerHTML instead of innerText if you want a string with the html tags
var onlyText = inputText.innerText.trim().replaceAll("\n\n","\n")
// Send data to the server, the response will be (value, indices). Pass it to the highlight function to be highlighted and rendered to the textbox.
/*
let axios = require('axios')
let data = {
"text": onlyText
}
axios.post('http://127.0.0.1:8000/predict', data)
.then(response => (highlight(response.data.value, response.data.indices)))
*/
// Example
var text = "We are trying this text just to see the output";
var indices = [{"start":1, "end":3},{"start":7, "end":8}];
highlight(text, indices)
}
const highlight = (text, indices) => {
// Get the object of the textbox
var inputText = document.getElementById("textbox");
// Split the string to an array of strings for easier processing
text = text.split(" ");
// enclose to be highlighted words with an HTML span of class highlight
for (var i = 0; i < indices.length; i++) {
text[indices[i].start] = "<span class='highlight'>" + text[indices[i].start]
text[indices[i].end -1] = text[indices[i].end -1] + "</span>"
}
// Join the array of strings into one string
var new_text = text.join(' ')
// Update the content of the textbox object with the highlighted text
inputText.innerHTML = new_text;
}
return (
<form noValidate autoComplete="off">
<p
className="textbox"
variant="outlined"
id="textbox"
onPaste={handlePaste} /** Handle the paset event to avoid pasting the style*/
fontWeight = {500}
contentEditable = {true}
></p>
<Button onClick={handleClear}>Clear</Button>
<Button onClick={handleSubmit}>Submit</Button>
</form>
);
};
export default HomePage;
Added to App.css
.highlight {
background-color: yellow;
}
.textbox {
border: 1px solid #000000;
}
Here are some stackoverflow questions that helped me:
get the text content from a contenteditable div through javascript
Javascript trick for "paste as plain text" in execCommand
welcome to StackOverflow.
I don't see anyway to solve your problem with react, or any related package. One way I could see it done, would be replacing your TextField with a native <p> with the attribute contenteditable="true", and styling that as you wish, maybe to look as close as possible to the original TextField.
Please tell me if you manage to do it, with my alternative solution or otherwise

How to get code input as component in react.js

I'm creating a webpage that has a code editor where the user can write code in react.js and run the test script on the terminal with the code that the user input. I have a test script using #testing-library/react. I'd like to get a code input from the text editor which is currently just a string and render it as a component on the test file so that I can run the test with the user's code input.
The test file is looking like this.
import { render } from "#testing-library/react";
import ToggleMessage from "./ToggleMessage";
import "#testing-library/jest-dom/extend-expect";
test("Render ToggleMessage component and check if it has text:'Want to buy a new car?'", () => {
const { getByText } = render(<ToggleMessage />); //<= Here I want to render codeInput as component.
const linkElement = getByText(/Want to buy a new car?/i);
expect(linkElement).toBeInTheDocument();
});
This is ToggleMessage.js where getting codeInput as a prop from a text editor.
import React, { useState, useRef } from "react";
function ToggleMessage({ codeInput }) {
const [display, setDisplay] = useState("none");
const toggle = () => {
display === "none" ? setDisplay("block") : setDisplay("none");
};
return (
<div>
<a href="#" onClick={toggle}>
Want to buy a new car?
</a>
<p style={{ display }}>Call +11 22 33 44 now!</p>
</div>
);
}
export default ToggleMessage;
Are there any ways to pass the codeInput prop to the test file and render it as a component? Any suggestions or help would be appreciated. Thank you!

Search Input with Semantic UI React OnChange Very Slow

I'm doing a simple filter on my data using the Semantic UI React 'Input' Component. The data loads first, and then i apply the search filter to narrow down the data based on the user input.
It works, but when typing, it's very slow. I saw another user with a similar issue and someone mentioned onBlur but that doesn't seem to be working for me. Here is my Search component, which is passing a search state back to one of my other components which updates the data. Anyone have any recommendations here?
import React from "react";
import { connect } from "react-redux";
import { Input } from "semantic-ui-react";
import { searchChange, clearSearch } from "../reducers/searchReducer";
const Search = props => {
const handleSearch = event => {
props.searchChange(event.target.value.toLowerCase());
};
const style = {
marginBottom: 10
};
return (
<div style={style}>
<Input
icon="search"
placeholder="Enter filter..."
onChange={handleSearch}
/>
</div>
);
};
const mapStateToProps = state => {
return {
search: state.search,
filter: state.filter
};
};
export default connect(mapStateToProps, {
searchChange,
// filterChange,
clearSearch
})(Search);

Categories