0

When a user types, the text is turned into an array, separated by " ". A <ul> element is created and occupied by one <li> for each member of the array, each containing its respective word. These are given the class list-group-item-danger by default, as in Bootstrap. When clicked, this class should be removed and replaced with list-group-item-success.

There is a default <ul> element. The <li> members within it respond as expected, with the colour changing when clicked. However, once those are removed and the dynamically created <li> elements are inserted, they no longer function and remain with the list-group-item-danger class which they already had.

HTML:

<div class="jumbotron">
    <div class="container">
        <div class="row">
            <div class="col-lg-10 col-lg-offset-1">
                <div class="input-group">
                    <input id="wordsearch" type="text" class="form-control wordsearch" placeholder="" />                      
                    <span id="go" class="input-group-btn">
                        <button class="btn btn-default" type="submit">
                            <span class="glyphicon glyphicon-search"></span>
                        </button>
                    </span>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="container">
    <div id="wordFilter">
        <ul class="list-group word-filter">
            <li class="list-group-item list-group-item-danger">Your</li>
            <li class="list-group-item list-group-item-danger">words</li>
            <li class="list-group-item list-group-item-danger">appear</li>
            <li class="list-group-item list-group-item-danger">here</li>
            <li class="list-group-item list-group-item-danger">as</li>
            <li class="list-group-item list-group-item-danger">you</li>
            <li class="list-group-item list-group-item-danger">type.</li>
        </ul>
    </div>
</div>

CSS:

.word-filter li{
    display: inline;
}

JQuery:

$(document).ready(function() {
    $('#wordsearch').keyup(function() {
        var inputVal = $('#wordsearch').val();
        var inputs = inputVal.split(" ");
        var ul = document.createElement("ul");
        ul.setAttribute("class", "list-group word-filter");
        $(inputs).each(function() {
            var li = document.createElement("li");
            li.setAttribute("class", "list-group-item list-group-item-danger");
            li.appendChild(document.createTextNode(this));
            ul.appendChild(li);
        });
        $('#wordFilter').empty();
        $('#wordFilter').append(ul);
    });
/* Colour Switching Function */
    $('div#wordFilter ul li').click(function() {
        if($(this).hasClass('list-group-item-success')) {
            $(this).addClass('list-group-item-danger');
            $(this).removeClass('list-group-item-success');
        } else {
            $(this).addClass('list-group-item-success');
            $(this).removeClass('list-group-item-danger');
        }
    });
});
Muckee
  • 474
  • 1
  • 8
  • 26

3 Answers3

1

Consider using the on() function to handle wiring up events for dynamically created elements :

// This will handle any current and future click events
// for elements that match this selector
$('#wordFilter').on('click','ul li', function() {
    // Equivalent code to your previous statements
    $(this).toggleClass('list-group-item-success list-group-item-danger');
});

The click() function operates differently from this and will only wire up the event for those that currently exist at the time of the function call.

Muckee
  • 474
  • 1
  • 8
  • 26
Rion Williams
  • 74,820
  • 37
  • 200
  • 327
  • Thanks but I still don't get a response when I use the click() function. I have tried using your code, as well as with the following, but neither work. $('div#wordFilter').on(click, 'ul li', function() { if($(this).hasClass('list-group-item-success')) { $(this).addClass('list-group-item-danger'); $(this).removeClass('list-group-item-success'); } else { $(this).addClass('list-group-item-success'); $(this).removeClass('list-group-item-danger'); } }); – Muckee Feb 06 '17 at 15:22
  • `.on("click", function...` works exactly the same way as `.click(function...` - the element must exist at the time. To use event delegation, you need to add the additional selector argument (see linked duplicate). http://api.jquery.com/on/ – freedomn-m Feb 06 '17 at 15:38
  • I had to combine this with the code `.toggleClass('list-group-item-success list-group-item-danger');` from @zer00ne 's answer to create a working solution. – Muckee Feb 06 '17 at 17:15
1

Since your li's elements are added dynamically to the DOM you should use event delegation .on(), ( I suggest the use of jQuery toggleClass() method ) :

$('body').on('click', '#wordFilter ul li', function() {
    $(this).toggleClass('list-group-item-success list-group-item-danger');
});

Hope this helps.

$(document).ready(function() {
  $('#wordsearch').keyup(function() {
    var inputVal = $('#wordsearch').val();
    var inputs = inputVal.split(" ");
    var ul = document.createElement("ul");
    ul.setAttribute("class", "list-group word-filter");

    $(inputs).each(function() {
      var li = document.createElement("li");
      li.setAttribute("class", "list-group-item list-group-item-danger");
      li.appendChild(document.createTextNode(this));
      ul.appendChild(li);
    });
    $('#wordFilter').empty();
    $('#wordFilter').append(ul);
  });


  $('#wordFilter').on('click', 'li', function() {
    $(this).toggleClass('list-group-item-success list-group-item-danger');
  });
});
.word-filter li {
  display: inline;
}
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<div class="jumbotron">
  <div class="container">
    <div class="row">
      <div class="col-lg-10 col-lg-offset-1">
        <div class="input-group">
          <input id="wordsearch" type="text" class="form-control wordsearch" placeholder="" />
          <span id="go" class="input-group-btn">
            <button class="btn btn-default" type="submit">
              <span class="glyphicon glyphicon-search"></span>
            </button>
          </span>
        </div>
      </div>
    </div>
  </div>
</div>
<div class="container">
  <div id="wordFilter">
    <ul class="list-group word-filter">
      <li class="list-group-item list-group-item-danger">Your</li>
      <li class="list-group-item list-group-item-danger">words</li>
      <li class="list-group-item list-group-item-danger">appear</li>
      <li class="list-group-item list-group-item-danger">here</li>
      <li class="list-group-item list-group-item-danger">as</li>
      <li class="list-group-item list-group-item-danger">you</li>
      <li class="list-group-item list-group-item-danger">type.</li>
    </ul>
  </div>
</div>
Zakaria Acharki
  • 66,747
  • 15
  • 75
  • 101
  • @freedomn-m you mean like i've suggested here.. – Zakaria Acharki Feb 06 '17 at 15:40
  • Yes, this is the correct format for using event delegation with `.on()`. I thought about adding "see the other answer", but went with "see linked duplicate" as all the information is there. – freedomn-m Feb 06 '17 at 15:42
  • Yes true you've suggested a valid dup.. marked – Zakaria Acharki Feb 06 '17 at 15:44
  • The same question gets asked about once every 30 minutes... :) – freedomn-m Feb 06 '17 at 15:45
  • Thanks guys but still not working. I have tried using toggleClass and that just removes all functionality, so the template 'Your words appear here as you type' text doesn't change either, whereas using my original method it changes that template text, but stops working once its replaced. – Muckee Feb 06 '17 at 17:03
1

You delegate the event by selecting document and using the .on() method. In order to determine which <li> was clicked, you can use event.target. I also changed your class methods narrowing it down to one line using .toggleClass()

/* Colour Switching Function */
  /* By selecting the document and using .on() method...
  || ...the document will listen for clicks instead of individual <li>
  || Using the capture, target, and bubbling event phases, you can...
  || use the Event Object's .target property. The event.target...
  || property will determine the actual element that you clicked...
  || ...thereby the callback will act on the correct <li>.
  */
  // Instead of changing classes with add/removeClass() use toggleClass()

  $(document).on('click', function(e) {
    var tgt = e.target;
    $(tgt).toggleClass('list-group-item-success list-group-item-danger');
  });

SNIPPET

$(document).ready(function() {
  $('#wordsearch').keyup(function() {
    var inputVal = $('#wordsearch').val();
    var inputs = inputVal.split(" ");
    var ul = document.createElement("ul");
    ul.setAttribute("class", "list-group word-filter");
    $(inputs).each(function() {
      var li = document.createElement("li");
      li.setAttribute("class", "list-group-item list-group-item-danger");
      li.appendChild(document.createTextNode(this));
      ul.appendChild(li);
    });
    $('#wordFilter').empty();
    $('#wordFilter').append(ul);
  });
  
  /* Colour Switching Function */
  $(document).on('click', function(e) {
    var tgt = e.target;
      $(tgt).toggleClass('list-group-item-success list-group-item-danger');


  });
});
.word-filter li {
  display: inline;
}
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

<div class="jumbotron">
  <div class="container">
    <div class="row">
      <div class="col-lg-10 col-lg-offset-1">
        <div class="input-group">
          <input id="wordsearch" type="text" class="form-control wordsearch" placeholder="" />
          <span id="go" class="input-group-btn">
                        <button class="btn btn-default" type="submit">
                            <span class="glyphicon glyphicon-search"></span>
          </button>
          </span>
        </div>
      </div>
    </div>
  </div>
</div>
<div class="container">
  <div id="wordFilter">
    <ul class="list-group word-filter">
      <li class="list-group-item list-group-item-danger">Your</li>
      <li class="list-group-item list-group-item-danger">words</li>
      <li class="list-group-item list-group-item-danger">appear</li>
      <li class="list-group-item list-group-item-danger">here</li>
      <li class="list-group-item list-group-item-danger">as</li>
      <li class="list-group-item list-group-item-danger">you</li>
      <li class="list-group-item list-group-item-danger">type.</li>
    </ul>
  </div>
</div>
zer00ne
  • 41,936
  • 6
  • 41
  • 68