ContentEditable on nextjs, update not showing in state - javascript

i got a component for a message. I got there a ContentEditable component https://www.npmjs.com/package/react-contenteditable i use there because i would need to add contacts in this "textarea" but i needed to implement html code inside for separate every tag, give them a color, etc.
The problem is that i want to prevent characters, user will not be able to add letters, just numbers, comma, and space. I created a function for this for use "onChange", it shows me the right data in the console. But in the frame it stills show the ilegal characters that the user has typed in. The correct data is in the state, but it does not update on the ContentEditable frame.
const contentEditable = React.createRef();
let state = { html: "0424" };
const handleChange = evt => {
let htmlf = evt.target.value.replace(/\D/g,''); ;
console.log(htmlf);
state = { html: htmlf };
console.log(state);
};
<ContentEditable
innerRef={contentEditable}
html={state.html} // innerHTML of the editable div
disabled={false} // use true to disable editing
onChange={handleChange} // handle innerHTML change
tagName="numero" // Use a custom HTML tag (uses a div by default)
id="contacts"
/>
SOLUTION
Just declare the component state in a different way.
constructor(props) {
super(props);
this.state = {
html: "0424"
};
}
contentEditable = React.createRef();
handleChange = evt => {
let htmlf = evt.target.value.replace(/\D/g, "");
console.log(htmlf);
this.setState({ html: htmlf })
console.log(this.state);
};
<ContentEditable
innerRef={this.contentEditable}
html={this.state.html} // innerHTML of the editable div
disabled={false} // use true to disable editing
onChange={this.handleChange} // handle innerHTML change
tagName="numero" // Use a custom HTML tag (uses a div by default)
id="contacts"
/>

Related

react-jsonschema-form input box out of focus when ObjectFieldTemplate is used

I have rjsf version ^5.0.0-beta.10 installed in package.json and am able to render a proper Form using react-jsonschema-form. The problem is that I'm using ObjectFieldTemplate and every time I enter a character in one of the string input boxes, the box goes out of focus and I have to click on the box again to be able to type anything.
I have read https://github.com/rjsf-team/react-jsonschema-form/issues/2106, which suggested me to move the ObjectFieldTemplate outside of the custom Form definition. I did that and it does not work. I have also read Custom widget with input loses focus in react-jsonschema-form when formData is passed as a prop to the form, which is an advice about setting state, but I'm using functional components rather than class components, so I'm not sure if it's applicable.
The code looks like:
import validator from "#rjsf/validator-ajv6";
import Form from "#rjsf/mui";
const ObjectFieldTemplate = (props) => {
// some logic to be computed
return (
<div>
<h3>{props.title}</h3>
<p>{props.description}</p>
{props.properties.map(function (field) {
// logic to determine the style
return (<fieldset style={style} key={uuidv4()}>{field.content}</fieldset>);
})}
</div>
);
}
const JsonSchemaForm = (props) => {
// define schema and uiSchema
const onSubmit = ({formData}, e) => {
// some logic
}
const onError = (errors) => {console.log(errors);}
return (<Form
schema={schema}
validator={validator}
formData={data}
uiSchema={uiSchema}
onSubmit={onSubmit}
onError={onError}
templates={{ ObjectFieldTemplate }}
/>);
}
Solved. I'm not sure why, but it appears that setting key={uuidv4()} is an expensive computation step that forces the input box to be out of focus.

Add onclick or eventListener in insertAdjacentHTML in react-js

I am building a simple react app for learning purpose, I just started learning react-js, I was trying to add paragraph dynamically on user action and it worked perfectly But I want to add an onClick event in insertAdjacentHTML (basically innerHTML).
But onclick event is not working in innerHTML
app.js
const addParagraph = () => {
var paragraphSpace = document.getElementById('container')
paragraphSpace.insertAdjacentHTML('beforeend', `<p>I am dynamically created paragraph for showing purpose<p> <span id="delete-para" onClick={deleteParagraph(this)}>Delete</span>`
}
const deleteParagraph = (e) => {
document.querySelector(e).parent('div').remove();
}
class App extends React.Component {
render() {
return (
<div>
<div onClick={addParagraph}>
Click here to Add Paragraph
</div>
<div id="container"></div>
</div>
)
}
}
What I am trying to do ?
User will be able to add multiple paragraphs and I am trying to add a delete button on every paragraph so user can delete particular paragraph
I have also tried with eventListener like :-
const deleteParagraph = () => {
document.querySelector('#delete').addEventListener("click", "#delete",
function(e) {
e.preventDefault();
document.querySelector(this).parent('div').remove();
})
}
But It said
deleteParagraph is not defined
I also tried to wrap deleteParagraph in componentDidMount() But it removes everything from the window.
Any help would be much Appreciated. Thank You.
Do not manipulate the DOM directly, let React handle DOM changes instead. Here's one way to implement it properly.
class App extends React.Component {
state = { paragraphs: [] };
addParagraph = () => {
// do not mutate the state directly, make a clone
const newParagraphs = this.state.paragraphs.slice(0);
// and mutate the clone, add a new paragraph
newParagraphs.push('I am dynamically created paragraph for showing purpose');
// then update the paragraphs in the state
this.setState({ paragraphs: newParagraphs });
};
deleteParagraph = (index) => () => {
// do not mutate the state directly, make a clone
const newParagraphs = this.state.paragraphs.slice(0);
// and mutate the clone, delete the current paragraph
newParagraphs.splice(index, 1);
// then update the paragraphs in the state
this.setState({ paragraphs: newParagraphs });
};
render() {
return (
<div>
<div onClick={this.addParagraph}>Click here to Add Paragraph</div>
<div id="container">
{this.state.paragraphs.map((paragraph, index) => (
<>
<p>{paragraph}</p>
<span onClick={this.deleteParagraph(index)}>Delete</span>
</>
))}
</div>
</div>
);
}
}
insertAdjecentHTML should not be used in javascripts frameworks because they work on entirely different paradigm. React components are rerendered every time you change a component state.
So you want to manipulate look of your component by changing its state
Solution:
In constructor initialize your component's state which you will change later on button click. Initial state is array of empty paragraphs.
constructor() {
super()
this.state = {
paragraphs:[]
}
}
And alter that state on button click - like this:
<div onClick={addParagraph}>
Add Paragraph function
const addParagraph = () =>{
this.state = this.state.push('New paragraph')
}
Rendering paragraphs
<div id="container">
this.state.paragraphs.map(paragraph =>{
<p>{paragraph}</p>
})
</div>
Additional tip for ReactJS in 2022 - use Functional components instead of Class components

I want the input data to go into the title and the textarea data to go into the content

import React from 'react';
export default class CreateNote extend React.component {
constructor(props) {
super(props);
this.state = {note:{title:" ",content:" "} };
console.log(this.state);
}
const inputEvent = (event) => {
const value = event.target.value;
const name = event.target.name;
this.setState({
note:{title: ,content: }
})
}
render(){
return(
<input
type="text"
placeholder="Title"
name="title"
id=""
value={note.title}
onChange={inputEvent}
/>
<textarea
name="contant"
id=""
value={note.contant}
cols=""
rows=""
placeholder="Write a Notes"
onChange={inputEvent}
onClick={expanded}>
</textarea>
)
}
When I write text in the input field and textarea then do not go data to note state. I want the input data to go into the title and the textarea data to go into the content.
Now I will write what on setState? I want to see result in the console.
Tip: Your code is riddled with errors and typos (e.g., CreateNote extend React.component instead of CreateNote extends React.Component , writing const for a function inside a Class Component, contant instead of content). For better chances of getting a help, kindly post the working code that you have, so that duplicating the issue becomes easier for the people looking to help you.
Now on to the solution. If you are a beginner, the best way to get what you want is to make separate functions - one that is triggered when the text inside the input is changed, and the other which is triggered when the text inside textarea is changed.
Note that you have kept title and content inside a state object note. This means in order to change title or content, you have to update the entire note object. Be careful if you update just one key of note without persisting the other one (e.g., if you update title only and want to leave content unaffected), you should use the spread operator ... which helps to clone the object's values, so then after that you can update the value of the key you want.
titleChange = (e) => {
this.setState({
note: {
...this.state.note,
title: e.target.value
}
});
};
contentChange = (e) => {
this.setState({
note: {
...this.state.note,
content: e.target.value
}
});
};
Update, a cleaner approach: We can also use the "name" attribute of the input and textarea to our benefit and combine the two functions into one (I've named it inputChange )
inputChange = (e) => {
this.setState({
note: {
...this.state.note,
[e.target.name]: e.target.value
}
});
};
You can find a working CodeSandBox here. Note that using spread operator will not be necessary if you move out the required fields title and content out from notes and make them state variables directly. Check out the AppWithoutNote.js file to see how it can be implemented.

Select specific text in the editorState

I'm creating a rich text editor using draftjs. Here is the minimal codesandbox so you have an idea of what the issue is.
So I have an helper function getCurrentTextSelection that return me the text that I'm selecting:
const getCurrentTextSelection = (editorState: EditorState): string => {
const selectionState = editorState.getSelection();
const anchorKey = selectionState.getAnchorKey();
const currentContent = editorState.getCurrentContent();
const currentContentBlock = currentContent.getBlockForKey(anchorKey);
const start = selectionState.getStartOffset();
const end = selectionState.getEndOffset();
const selectedText = currentContentBlock.getText().slice(start, end);
return selectedText;
};
When I click outside the TextEditor, the focus is lost so the text isn't selected (but stay the selected one for the editorState).
Is there a programmatic way to reselect this text using the editorState? So that when you click the Select text again button, the text in the TextEditor is selected.
I believe what you're looking to do is restore focus to the editor. If all you do is click outside the editor, the selection state doesn't change (which is why your selected text remains the same). If you then restore focus the same selection becomes visible again, without any changes to editorState.
Draft.js has some documentation about how to do this: https://draftjs.org/docs/advanced-topics-managing-focus/
The Editor component itself has a focus() method which, as you might expect, restores focus to the editor. You can gain access to the component instance with a ref:
const editorRef = React.useRef<Editor>(null)
const selectAgain = () => {
editorRef.current.focus()
};
Then connect the ref to the component and add the click handler to the button:
<div>
<Editor
editorState={editorState}
onChange={onEditorStateChange}
placeholder={placeholder}
ref={editorRef} // added ref
/>
<h2>Selected text:</h2>
<p>{getCurrentTextSelection(editorState)}</p>
// added click handler
<button onClick={selectAgain}>Select text again</button>
</div>
Complete example: https://codesandbox.io/s/flamboyant-hill-l31bn
Maybe you can store the selectedText into EditorState
Using
EditorState.push( editorState, contentState, changeType)
More Info

Issues with updating the State - React

I'm having issues in updating the state values, I'm rendering a external component using Map, and hence not able to access this. So on click of the component I'm not able to call the handleClick function to update the state values..
Here is the state :
this.state = {
attributes : {
hours : {
},
cost : 0,
amenities : defaultAmenities
},
primary_category : "General"
}
Where defaultAmenities is a external file with large javascript object.
The render function :
render() {
let basicAmenities, extendedAmenities
let basicAmenitiesList = [], extendedAmenitiesList = []
//Wrong way of storing this
let _this = this;
}
... More Logics / Switch Cases ...
let amenitiesList = basicAmenitiesList.map(function(item, index){
return <Attribute key={index} name={item.amenity_id} type={item.title} icon={item.icon} selected={item.isSelected} value="" onClick={_this.handleClick.bind(_this)}/>
})
And the attribute component
<div className="attribute-grid" onClick={this.props.onClick}>
...
</div>
Handle click is a function to setState on click of Attribute.
handleClick(e) {
console.log(e.target);
}
On click of the attribute, I need to update the state. The result of console log is attached below. I need to target the input values, but since it return the entire div, how do i get the values of name/value/placeholder?
<div class="attribute-grid-block" data-reactid=".0.2.0.3.0.1.$0.0"><div class="attribute-grid-img" data-reactid=".0.2.0.3.0.1.$0.0.0"><img src="petsIcon" data-reactid=".0.2.0.3.0.1.$0.0.0.0"></div><div class="attribute-grid-info" data-reactid=".0.2.0.3.0.1.$0.0.1"><h6 data-reactid=".0.2.0.3.0.1.$0.0.1.0">Pets</h6><input type="text" name="pets" placeholder="NO INFO FOUND" value="" disabled="" data-reactid=".0.2.0.3.0.1.$0.0.1.1"></div></div>
you can get what you need from the target. but you need to set the onClick on the element that you want it to be the target and then you will have it:
handleClick(e) {
const name = e.target.name;
const value = e.target.value;
const placeholder = e.target.placeholder;
console.log(placeholder);
}
if you want to set the onClick elsewhere you will need to send the values you want, so inside Attribute component you will have a function that will be invoke on click and call the this.props.onClick({ name: '', value: ''});
if you need to use this inside this function, and you are using react with classes. you can write this:
handleClick = (e) => {
console.log(this);
}

Categories

Resources