onChange event not triggering on wired-textarea
jrej-dev opened this issue · 8 comments
I am using the wired-textarea element in a react application.
The value property does work but it is impossible to update state with a new value as the function does not trigger with onChange. I'll use the regular textarea for now as it is working fine with it.
Hello Jrejoire,
Can you provide a code sample ?
wired-textarea dispatch a custom element, and react is notorious for not handling those well as React is using its own event system.
You might need to create a ref to the component and addEventListener to this ref.
https://vaadin.com/learn/tutorials/using-web-components-in-react
Regards,
Adrien
Good afternoon Adrien,
Thank you for your quick response.
I'll look into the use of ref for the issue.
Here's the code sample if needed.
Have a nice day.
Regards,
Jrej
import React, {useState} from 'react';
import StoreContext from '../../stores/AppStore';
import 'wired-elements';
const CommentInput = ({ content }) => {
const store = React.useContext(StoreContext);
const permlink = "re-"+ content.permlink + "-" + Date.now();
const [body, setBody] = useState("");
const handleReplyChange = (e) => {
setBody(e.target.value);
}
const handleReplySubmit = (author) => {
//sending data to store function
store.comment(content.author, content.permlink, author, permlink, "", body, content.json_metadata)
}
return (
<div className="active comment-banner">
<form onSubmit={(e) => {
e.preventDefault();
handleReplySubmit(store.userDetail.name)}
}>
<div className="comment-body">
<wired-textarea
placeholder="Your reply..."
rows="6"
onChange={handleReplyChange}
value={body}
/>
</div>
<div className="comment-bottom-banner flex-start pa-hh">
<button type="submit" className="send-btn">Send</button>
<p className="pointer" onClick={() => {
store.toggleReplyIsActive(content.permlink)}
}>
Cancel
</p>
</div>
</form>
</div>
)
}
export default CommentInput;
Not tested, but this is what I would try with useRef hooks:
import React, {useState, useRef} from 'react';
import StoreContext from '../../stores/AppStore';
import 'wired-elements';
const CommentInput = ({ content }) => {
const store = React.useContext(StoreContext);
const permlink = "re-"+ content.permlink + "-" + Date.now();
const [body, setBody] = useState("");
const textArea = useRef(null);
const handleReplyChange = (e) => {
setBody(e.target.value);
}
const handleReplySubmit = (author) => {
//sending data to store function
store.comment(content.author, content.permlink, author, permlink, "", body, content.json_metadata)
}
textArea.addEventListener('change', handleReplyChange);
return (
<div className="active comment-banner">
<form onSubmit={(e) => {
e.preventDefault();
handleReplySubmit(store.userDetail.name)}
}>
<div className="comment-body">
<wired-textarea
placeholder="Your reply..."
rows="6"
ref={textArea}
value={body}
/>
</div>
<div className="comment-bottom-banner flex-start pa-hh">
<button type="submit" className="send-btn">Send</button>
<p className="pointer" onClick={() => {
store.toggleReplyIsActive(content.permlink)}
}>
Cancel
</p>
</div>
</form>
</div>
)
}
export default CommentInput;
As it is a custom event*, I don't know exactly if the event would have a target property, but you can console.log the event to see where the value is contained ;) (maybe in event.detail ?)
regards,
AP.
Oh I see. Thanks for the possible solution. For now I get the "textArea.addEventListener is not a function" error but I'll look more into this. I'll let you know if I come up with an alternative.
I had time for a quick test, here is how you can retrieve the value from the event.
The event is a bit weird, because it's a custom event that wraps a native event ;)
useEffect is necessary here as the custom element is mounted once the react component is mounted ("componentDidMount")
import React, {useRef, useEffect} from 'react';
import 'wired-textarea';
function App() {
const textArea = useRef(null);
const handleEvent = e => console.log(e.detail.sourceEvent.target.value);
useEffect(() => {
textArea.current.addEventListener('input', handleEvent);
return () => {
textArea.current.removeEventListener('input', handleEvent)
}
}, [])
return (
<wired-textarea ref={textArea} elevation="5"></wired-textarea>
);
}
export default App;
EDIT: cleanup with removeEventListener + more concise example
Great! It worked. Thanks a ton.
These hand drawn components are so awesome. It would have been a shame not to use them in all occasion. ;-)
Thanks @apennamen