Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React and blur event

I have a simple issue with React and event handling. My component looks like this (basically a table):

const MyList = ({ items, onBlur }) => <table onBlur={onBlur}}>     <thead>     <tr>         <th>ID</th>         <th>Title</th>         <th>Publisher</th>         <th>Year</th>         <th>Author</th>         <th>System</th>         <th/>     </tr>     </thead>     <tbody>     {items.map(item => <MyListRow key={item.Id} item={item}/>)}     </tbody> </table>; 

I want the blur event to fire only if the focus goes out of the table. Instead the event fires on each child element of the table when it loses focus.

According to the docs React lets focus events bubble up.

The question is: How can I get my onBlur method fire only when the focus gets out of the table? IOW: How can I filter out and discard the unwanted events bubbling up so that I reveal only the events which indicate a lost of focus for the table?

like image 432
Peter Perot Avatar asked Jun 24 '16 17:06

Peter Perot


People also ask

How do you use blur events in React?

Reactjs provides an onBlur event bound to Input elements on the user form. onBlur is a javascript blur event, can attach a callback handler to this, called when input lost focus. onBlur is bounded to an input element with an event handler, Event handler is a function in a component, executed when input focus is lost.

What is onBlur event in React?

The onBlur event handler is called when focus has left the element (or left some element inside of it). For example, it's called when the user clicks outside of a focused text input. function Example() { return ( <input onBlur={(e) => { console.

What triggers blur event?

The blur event fires when an element has lost focus. The main difference between this event and focusout is that focusout bubbles while blur does not. The opposite of blur is focus . This event is not cancelable and does not bubble.

Is blur an event handler?

blur( [eventData ], handler ) An object containing data that will be passed to the event handler. A function to execute each time the event is triggered.


1 Answers

The problem is that a table doesn't actually have a concept of focus since it's not an input itself.

When the onBlur fires on the contained inputs we will check the relatedTarget of the onBlur event which should be set to the element that has RECEIVED focus (or null). We then use a function that will traverse upwards through parentNodes from that newly focused element and ensure that our event's currentTarget (the table) is not an ancestor of the newly focused element. If the condition passes it is assumed that the table no longer has any focus.

const focusInCurrentTarget = ({ relatedTarget, currentTarget }) => {    if (relatedTarget === null) return false;        var node = relatedTarget.parentNode;              while (node !== null) {      if (node === currentTarget) return true;      node = node.parentNode;    }      return false;  }    const onBlur = (e) => {    if (!focusInCurrentTarget(e)) {      console.log('table blurred');    }  }    const MyList = ({ items, onBlur }) => (    <table onBlur={onBlur}>      <thead>        <tr>          <th>ID</th>          <th>Title</th>          <th>Publisher</th>          <th>Year</th>          <th>Author</th>          <th>System</th>          <th/>        </tr>      </thead>      <tbody>        <tr>          <td>1</td>          <td>            <input type="text" />          </td>          <td>            <input type="text" />          </td>          <td>            <input type="text" />          </td>          <td>            <input type="text" />          </td>          <td>            <input type="text" />          </td>        </tr>      </tbody>    </table>  );        ReactDOM.render(    <MyList onBlur={onBlur} />,    document.getElementById('root')  );
table {    padding: 10px;    border: 1px solid red;  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>  <div id="root"></div>  <br />  <input type="text" />

References:

  • http://www.w3schools.com/jsref/event_onblur.asp
  • http://www.w3schools.com/jsref/event_currenttarget.asp
  • http://www.w3schools.com/jsref/event_focus_relatedtarget.asp
  • https://stackoverflow.com/a/2234986/2957138 (basis for our ancestor-checking function)

UPDATED:

Removed use of ReactDOM.findDOMNode

like image 157
TheZanke Avatar answered Oct 12 '22 16:10

TheZanke