react-contenteditable
react-contenteditable copied to clipboard
How to control events in the content?
Hello, I'm having trouble changing the content from a user action within the content itself. I am creating an input similar to facebook, that when the user informs a url, the system obtains the page's meta tags and a card is created as in the image below. However, by clicking on the "x" on the card I would like it to be removed, but I can't change the text.current anymore. Does anyone have any idea how to solve? Follow my code

import React, { useRef, useState, memo } from 'react';
import ContentEditable from 'react-contenteditable'
import sanitizeHtml from 'sanitize-html';
import { MdPhotoCamera, MdOndemandVideo, MdLink } from 'react-icons/md'
import api from 'lib/api';
const clean = content => sanitizeHtml(content, {
allowedTags: ['h5', 'p', 'a', 'nl', 'hr', 'br', 'div', 'iframe', 'img', 'button', 'span'],
disallowedTagsMode: 'discard',
allowedAttributes: {
a: ['href', 'name'],
iframe: ['src', 'width', 'height', 'frameborder', 'allow', 'allowfullscreen'],
img: ['src', 'style', 'class', 'alt'],
div: ['contenteditable', 'class', 'style'],
h5: ['class'],
p: ['class'],
button: ['class', 'type'],
span: ['aria-hidden', 'class']
},
// Lots of these won't come up by default because we don't allow them
selfClosing: ['img', 'br', 'hr'],
// URL schemes we permit
allowedSchemes: ['http', 'https', 'data'],
allowedSchemesByTag: {},
allowedSchemesAppliedToAttributes: ['href', 'src'],
allowProtocolRelative: true,
enforceHtmlBoundary: false,
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
transformTags: {
'img': (tagName, attribs) => ({
tagName,
attribs: {
...attribs,
style: 'max-width: 100%;',
}
}),
'iframe': (tagName, attribs) => ({
// My own custom magic goes here
tagName,
attribs: {
...attribs,
width: '100%;',
height: '300',
frameborder: '0',
allow: "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture",
allowfullscreen: true
}
})
}
});
const NewPost = () => {
const [loading, setLoading] = useState(false)
const text = useRef(clean(''))
const [loadedDiv, setLoadedDiv] = useState(false)
const handleChange = async ({ target: { value } }) => {
const href = value.match(/href="([^"]*")/g)
if (href) {
if (!loadedDiv) {
setLoading(true)
text.current = clean([value, bounce].join(''));
const { data } = await api.get(`/meta?url=${href[0].split('"')[1]}`)
text.current = clean([value, card(data)].join(''));
setLoading(false)
setLoadedDiv(true)
} else {
text.current = clean(value);
}
} else {
setLoadedDiv(false)
text.current = clean(value);
}
};
const handleClick = ({ target: { className } }) => {
console.log(className)
if (className === "close text-white position-absolute pos-top pos-right p-2 m-1 mr-2" || className === 'close_card_url') {
console.log(text);
text.current = '';
}
}
return (
<div className="card border mb-g">
<div className="card-body pl-4 pt-4 pr-4 pb-0">
<div className="d-flex flex-column">
<div className="d-flex flex-row border-top-0 border-left-0 border-right-0 mb-3">
<div className="d-inline-block align-middle mr-3">
<span className="profile-image rounded-circle d-block" style={{ backgroundImage: 'url("img/demo/avatars/avatar-admin.png")', backgroundSize: 'cover' }} />
</div>
<h5 className="mb-0 flex-1 text-dark fw-500">
Nome
<small className="m-0 l-h-n">
No que voçê está pensando?
</small>
</h5>
<span className="text-muted fs-xs opacity-70">
Agora
</span>
</div>
<ContentEditable
className="form-control p-3 h-auto border"
onClick={handleClick}
html={text.current}
disabled={loading}
onChange={handleChange} />
<div className="py-2 d-flex flex-row align-items-center flex-wrap flex-shrink-0">
<button className="btn btn-icon mr-2" onClick={e => e.preventDefault()}>
<MdLink className="text-muted" size={24} />
</button>
<button className="btn btn-icon mr-2" onClick={e => e.preventDefault()}>
<MdPhotoCamera className="text-muted" size={24} />
</button>
<button className="btn btn-icon" onClick={e => e.preventDefault()}>
<MdOndemandVideo className="text-muted" size={24} />
</button>
<button className="btn btn-dark shadow-0 ml-auto px-3">Publicar</button>
</div>
</div>
</div>
</div>
)
}
export default memo(NewPost);
You can use innerRef to get a reference to the editable DOM element. But in my opinion, your ssmart card should not be part of the contenteditable element.
@lovasoa
i Have similar query
I want to change the content with events based on conditions .
i am able to alter text.current
but the same is not rendered in the UI.
coinsider this example for illustration purpose.
const handleChange = evt => {
text.current = evt.target.value + 'A'
console.log(text.current); // gives evt.target.value + 'A' but renders only evt.target.value
}
<ContentEditable
html={text.current}
onChange={handleChange}
onBlur={handleBlur}
'/>
same problem here. any updated?
@lovasoa i Have similar query I want to change the content with events based on conditions . i am able to alter
text.current
but the same is not rendered in the UI.coinsider this example for illustration purpose.
const handleChange = evt => { text.current = evt.target.value + 'A' console.log(text.current); // gives evt.target.value + 'A' but renders only evt.target.value } <ContentEditable html={text.current} onChange={handleChange} onBlur={handleBlur} '/>