John Smith
John Smith

Reputation: 4353

Getting onClick eventargs for the parent of e.target & Adding custom data to propagating onClick args

Consider two divs. One is the parent. One is the child. The child partially overlaps the parent.

If any area above the parent (even if it's blocked by the child) is clicked, I want to receive the offsetX for the parent.

However, since it doesn't appear to be possible as the onClick evenargs are always calculated for the most nested element, I decided to use the following workaround:

  1. The child listens for onClicks. Once an onClick comes, it attaches some custom data to the eventargs.
const addOnClickInfo = (e) => {
    Object.assign(e, {customInfo: {startOfTimelineElementClicked: start}});
}

return <div onClick={addOnClickInfo} id='te' style={gridMemberStyle}></div>
  1. The parent listens for onClicks in capture mode (after the child's function is called) and uses the additional data attached by the child to calculate where the click was relative to the parent.
    const onClickHandler = e => {
        console.log(e.customInfo); // IMPORTANT LINE
        console.log(e.customInfo.startOfTimelineElementClicked); // IMPORTANT LINE

    // Here, with startOfTimelineElementClicked we've got enough data to calculate offsetX for the parent.

    };

First, is there some other, neater solution (getting eventargs for an element higher in DOM hierarchy than its child that is the actual event.target) to this problem?

Second: the data printed by console.logs above is delayed by one click. As the site loads, e.customInfo for the first click is undefined. From the second click and on it does contain a value, however it's always the one for the previous click. How does it happen?

UPDATE: While the above is true, if we substitute console.log(e) for console.log(customInfo), and inspect e in Google DevTools, it does seem to contain customInfo. Yet, a console.log(e.customInfo) literally a line later is undefined. Such as:

console.log(e) // Expanding it in Google DevTools; clearly has customInfo
console.log(e.customInfo) // undefined...?

Upvotes: 2

Views: 38

Answers (2)

John Smith
John Smith

Reputation: 4353

Silly mistake, captured events are called before non-captured events, not the other way around. This solves this issue.

It probably explains the DevTools issue as well. It loads object data only once you expand the object to view its contents, and by the time I manage to expand it, the event has already finished its bubbling phase.

Upvotes: 0

Dupocas
Dupocas

Reputation: 21317

You could achieve the same effect by appending a ref to your parent and pass down a function to retrieve the current offsetX from the parent

const Parent = () =>{
    const ref = useRef(null)

    const getOffset = ref.current ? ref.current.offsetX : null        

    return(
        <div ref={ref}>
            <Child getOffset={getOffset} />
        </div>
    )
}

And inside your Child

   const Child = ({ getOffset }) =>{
       const [offset, setOffset] = useState(getOffset())
       return (
           <>
               {`Current parent's offset: ${offset}`}
               <button onClick={() => setOffset(getOffset())}>Refresh offset </button>
           </>
       )
   }

Upvotes: 2

Related Questions