TheGuy
TheGuy

Reputation: 477

How to click function for an auto built li list

In my application, it parses data from an xml file and then show the data in a <li> list. So there is a <ul> list and a loop for the xml file to put some specific data in each <li> tag. It successfully reads the xml file and creates the list, but the problem is that the list is kind of not active. For example, I made a click function so it gives alert("done!"); when a <li> is clicked, but it is not working.

Here is my code:

var tracksArray = [];
$.ajax({
  url: 'https://dl.dropboxusercontent.com/u/33538012/playlist.xml',
  dataType: "xml",
  success: parse,
  error: function() {
    alert("Error: Something went wrong");
  }
});

function parse(document) {
  $(document).find("track").each(function() {
    tracksArray.push($(this).find('url').text());

    $(".panel1 ul").append(
      "<li id='row" + tracksArray.length + "'>" +
      "<p class='title'>" + $(this).find('title').text() + "</p>" +
      "</li>"
    );

  });
}


$(".panel1 ul li").on("click", function() {
  alert("done!");
})
div.app {
  margin: 50px auto;
  width: 400px;
  height: 400px;
  border-radius: 10px;
  overflow: hidden;
  position: relative;
}
div.app > .blur {
  width: 100%;
  height: 100%;
  -webkit-filter: blur(5px);
}
div.mainSection,
div.dashboard {
  position: absolute;
  left: 0px;
  text-align: center;
  color: #fff;
  font-size: 20px;
}
div.mainSection {
  width: 100%;
  height: 85%;
  background: rgba(0, 0, 0, 0.5);
  top: 0;
}
div.dashboard {
  width: 100%;
  height: 15%;
  background: rgba(255, 0, 0, 0.5);
  bottom: 0;
}
div.mainSection > .panel1,
div.mainSection > .panel2,
div.mainSection > .panel3 {
  width: 100%;
  Height: 100%;
  Background: rgba(0, 0, 0, 0.5);
  position: absolute;
  left: 0px;
  top: 0px;
}
div.mainSection > .panel3 > p {
  margin-top: 80px;
}
.grid-button {
  background: none;
  border: none;
  padding: 3px;
  width: 100%;
}
.grid {
  display: inline-block;
  height: 4px;
  position: relative;
  width: 32px;
  transition: all 0.3s ease-in-out;
}
.grid:after,
.grid:before {
  content: '';
  position: absolute;
  background-color: #FFF;
  display: inline-block;
  height: 4px;
  left: 0;
  width: 32px;
  transition: all 0.3s ease-in-out;
}
.grid.open {
  background-color: #FFF;
}
.grid.open:after {
  top: 10px;
}
.grid.open:before {
  top: -10px;
}
.grid.close {
  background-color: transparent;
  transform: scale(0.9);
}
.grid.close:after,
.grid.close:before {
  top: 0;
  transform-origin: 50% 50%;
}
.grid.close:before {
  transform: rotate(135deg);
}
.grid.close:after {
  transform: rotate(45deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="app">
  <div class="blur"></div>
  <div class="mainSection">
    <div class="panel1">
      <ul></ul>
    </div>
    <div class="panel2" style="display: none;"></div>
    <div class="panel3" style="display: none;"></div>
  </div>
  <div class="dashboard"></div>
</div>

As you can see, the last part of the my js code is for giving alert if a <li> is clicked, but nothing happens.

Does anyone know why is that?

Upvotes: 0

Views: 57

Answers (6)

Bogie
Bogie

Reputation: 153

Because you add the onclick listener directly to the li element, it will not work if the li is dinamicly appended/removed from the ul via AJAX callback. When you first attached the onclick to the li, which are not already appended to the ul, it will do nothing.

It can be done by attaching the onclick listener to the ul itself. then checks whether the target li clicked within the ul.

$('panel1 ul').on('click', 'li', function() {
   console.log('list clicked!');
});

That means every clicked elements within the panel1 ul will be delegated up to ul. And if it is li, the callback will be executed.

Upvotes: 1

Alfred
Alfred

Reputation: 21396

Give a class to your lis like;

$(".panel1 ul").append(
  "<li class="lis" id='row" + tracksArray.length + "'>" +
  "<p class='title'>" + $(this).find('title').text() + "</p>" +
  "</li>"
);

And then try;

$(".lis").live("click", function(){
    alert("done!");
});

Upvotes: 1

ketan
ketan

Reputation: 19341

You can do like following way.

Here apply concept of Event Propagation

So you can get click event like:

$('.panel1').on("click", "ul li", function(){

var tracksArray = [];
$.ajax({
  url: 'https://dl.dropboxusercontent.com/u/33538012/playlist.xml',
  dataType: "xml",
  success: parse,
  error: function() {
    alert("Error: Something went wrong");
  }
});

function parse(document) {
  $(document).find("track").each(function() {
    tracksArray.push($(this).find('url').text());

    $(".panel1 ul").append(
      "<li id='row" + tracksArray.length + "'>" +
      "<p class='title'>" + $(this).find('title').text() + "</p>" +
      "</li>"
    );

  });
}

$('.panel1').on("click", "ul li", function(){
  alert( $( this ).children( "p" ).text());
})
div.app {
  margin: 50px auto;
  width: 400px;
  height: 400px;
  border-radius: 10px;
  overflow: hidden;
  position: relative;
}
div.app > .blur {
  width: 100%;
  height: 100%;
  -webkit-filter: blur(5px);
}
div.mainSection,
div.dashboard {
  position: absolute;
  left: 0px;
  text-align: center;
  color: #fff;
  font-size: 20px;
}
div.mainSection {
  width: 100%;
  height: 85%;
  background: rgba(0, 0, 0, 0.5);
  top: 0;
}
div.dashboard {
  width: 100%;
  height: 15%;
  background: rgba(255, 0, 0, 0.5);
  bottom: 0;
}
div.mainSection > .panel1,
div.mainSection > .panel2,
div.mainSection > .panel3 {
  width: 100%;
  Height: 100%;
  Background: rgba(0, 0, 0, 0.5);
  position: absolute;
  left: 0px;
  top: 0px;
}
div.mainSection > .panel3 > p {
  margin-top: 80px;
}
.grid-button {
  background: none;
  border: none;
  padding: 3px;
  width: 100%;
}
.grid {
  display: inline-block;
  height: 4px;
  position: relative;
  width: 32px;
  transition: all 0.3s ease-in-out;
}
.grid:after,
.grid:before {
  content: '';
  position: absolute;
  background-color: #FFF;
  display: inline-block;
  height: 4px;
  left: 0;
  width: 32px;
  transition: all 0.3s ease-in-out;
}
.grid.open {
  background-color: #FFF;
}
.grid.open:after {
  top: 10px;
}
.grid.open:before {
  top: -10px;
}
.grid.close {
  background-color: transparent;
  transform: scale(0.9);
}
.grid.close:after,
.grid.close:before {
  top: 0;
  transform-origin: 50% 50%;
}
.grid.close:before {
  transform: rotate(135deg);
}
.grid.close:after {
  transform: rotate(45deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="app">
  <div class="blur"></div>
  <div class="mainSection">
    <div class="panel1">
      <ul></ul>
    </div>
    <div class="panel2" style="display: none;"></div>
    <div class="panel3" style="display: none;"></div>
  </div>
  <div class="dashboard"></div>
</div>

Hope it helps.

Upvotes: 1

ku&#39;
ku&#39;

Reputation: 102

A little change, move the click events into function parse. Since that ajax is asynchronous, when $.ajax is executed, it is executed in another thread and at the mean time $(".panel1 ul li").on("click",...) executes but finds the selector finds nothing. So moving click events into parse function ensures that the events is added after ajax is done.

function parse(document) {
  $(document).find("track").each(function() {
    tracksArray.push($(this).find('url').text());

    $(".panel1 ul").append(
      "<li id='row" + tracksArray.length + "'>" +
      "<p class='title'>" + $(this).find('title').text() + "</p>" +
      "</li>"
    );
  });
  $(".panel1 ul li").on("click", function() {
    alert("done!");
  });
}

Upvotes: 1

鄭元傑
鄭元傑

Reputation: 1647

That is because javascript run asyn.
When the data still waits for the ajax.

$(".panel1 ul li").on("click", function() {
alert("done!");
})

is already executed.
That's why it doesn't work!
You can simply put the on() function at the end of parse() function.
Here is my jsbin

https://jsbin.com/jicawe/edit?html,css,js,output

Upvotes: 1

Rajesh
Rajesh

Reputation: 24915

You can use a delegate:

$(document).on("click", "pane1 ul li", function(){ ... });

Sample

function createLI() {
  var html = "";

  for (var i = 0; i < 5;) {
    html += "<li>" + ++i + "</li>";
  }
  $("#list").append(html);
}

function registerEvents() {
  $(document).on("click", "#content ul li", function() {
    alert($(this).text());
  })
}

registerEvents();
createLI();
li {
  background: #eee;
  margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="content">
  <ul id="list"></ul>
</div>

Upvotes: 1

Related Questions