jipson
jipson

Reputation: 99

jQuery keydown callback listens only on outer <ul> rather than inner <li> element

Hey so here is the code demo I made

<!DOCTYPE html>
<html>
<head>
  <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
</head>
<body>
<ul contenteditable class="outerList">
<li class="innerElement">Hello</li>
<li class="innerElement">World</li>
<li class="innerElement">Hello World</li>
</ul>
<script>
    $(".outerList").keydown(function () {
      console.log("I am the outer ul");
    });
    $(".innerElement").keydown(function() {
      console.log("I am an inner element");
    });
    </script>
</body>
</html>

and here is the jsFiddle to run it

http://jsfiddle.net/scrbovyr/

Basically I have a content editable UL and I want to catch the enter key and pass in my own custom function. But I need to know which LI element the keydown event was thrown on. And as shown in the demo, I can only seem to tie a keydown event listener (or any event listener for that matter) to the outer UL element. Is there a way to attach the keydown event to each LI? Or is there at least a way to attach it to the UL but still tell which child it came from?

Thanks in advance, let me know if any additional information would help!

Upvotes: 2

Views: 778

Answers (2)

gfullam
gfullam

Reputation: 12045

You may check the node at the current selection

If you don't want to make each li a contenteditable element, you may get the element at the current selection or caret position and perform a check against it.

The embedded example shows how you would achieve this using the Web API Interface for contenteditable selections. (I tested this in Chrome, but it may need additional logic to achieve cross-browser compatibility).

It is also worth noting that you can bind some event listeners to the children of a contenteditable element. For example, the click event may be bound to the li elements as you can see in the embedded example.

$(document).ready(function() {
    
    function getCurrentNode() {
        var node = window.getSelection().getRangeAt(0).commonAncestorContainer;
        return node.nodeType === 1 ? node : node.parentNode;     
    }
    $('.outerList').on('click keyup', function (e) {
        var $target  = $(getCurrentNode()),
            $closest = $target.closest('b');
        console.log(e.type);
        console.log('I am the outer ul');
        console.log($target);
        
        // Optional. Filter by clostest selector.
        if ($closest.length) {
            console.log('Target matches selector', $closest);
        }
    });
    $('.innerElement').on('click', function (e) {
        console.log(e.type);
        console.log('I am an inner element');
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul contenteditable class="outerList">
      <li class="innerElement">Hello</li>
      <li class="innerElement"><i>Hello</i></li>
      <li class="innerElement"><b><i>Hello</i></b></li>
      <li class="innerElement"><b>Hello</b></li>
      <li class="innerElement">Hello</li>
      <li class="innerElement">Hello</li>
  </ul>

Upvotes: 2

taxicala
taxicala

Reputation: 21759

You will have to add contenteditable to your li elements in order to achieve that. You are setting contenteditable to your ul element, thus, the event will be binded to that element, you may edit the li elements, but they do not have contenteditable set, so the keyboard events won't be triggered for those elements.

<ul class="outerList">
    <li contenteditable class="innerElement">Hello</li>
    <li contenteditable class="innerElement">World</li>
    <li contenteditable class="innerElement">Hello World</li>
</ul>

And then:

$(".innerElement").keydown(function() {
  console.log("I am an inner element");
});

Upvotes: 2

Related Questions