rough-stuff/wired-elements

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