1

I am creating a calendar application using javascript. The calendar view is displayed using javascript (dom element) for which I have created a common method and I call the same for displaying the updated calendar view. When I'm clicking on a particular date, I need to update the display of the calendar, but it's getting updated only once when the event of the update is triggered. I have created a similar demo and am providing the same below.

<html>
<head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    <script>
        $(document).ready(() => {
            this.show();

            for (let i = 0; i < 10; i++) {
                $('#li-' + i).click(() => {
                    alert(i);
                    this.show();
                });
            }
        });

        function show() {
            let elem = document.getElementById('body');
            elem.innerHTML = "";

            let ul = document.createElement('ul');
            for (let i = 0; i < 10; i++) {
                let li = document.createElement('li');
                let text = document.createTextNode(i);
                li.appendChild(text);
                li.setAttribute('id', 'li-' + i);
                li.style.cursor = 'pointer';
                ul.appendChild(li);
                elem.appendChild(ul);
            }
        }
    </script>
</head>
<body>
    <div id="body"></div>
</body>
</html>

On this example, when I click on a 'li' element the click event is triggered and the alert box is shown. Also, the 'show()' method gets invoked for updating the view. However, when the another 'li' element is clicked, the event is not getting triggered.

2 Answers 2

3

Side note: I would definitely refactor your code.

The problem: this.show() is actually redrawing the entire div whose id is body.

Redrawing the elements (and removing the previous existing ones) unregisters the click events, which are not automatically registered. In your current scenario, you register the events once, just after rendering them, but you don't register them again after rendering the div again.

The solution is to just register again the events, by moving the for inside the show function.

$(document).ready(() => {
    this.show();
});

function show() {
  let elem = document.getElementById('body');
  elem.innerHTML = "";

  let ul = document.createElement('ul');
  for (let i = 0; i < 10; i++) {
      let li = document.createElement('li');
      let text = document.createTextNode(i);
      li.appendChild(text);
      li.setAttribute('id', 'li-' + i);
      li.style.cursor = 'pointer';
      ul.appendChild(li);
      elem.appendChild(ul);
  }
  
  for (let i = 0; i < 10; i++) {
      $('#li-' + i).click(() => {
          alert(i);
          this.show();
      });
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="body">

</div>

Sign up to request clarification or add additional context in comments.

5 Comments

Awesome! Thanks so much! Didn't have the idea of keeping the loop inside the show method. Thanks a lot.
Just a side note: Think about re-rendering every single time something changes: right now, you "only" have an iteration of 10 rows. However, think about what happens if elements suddenly become 1000. It would be a better approach to think about altering existing DOM elements, rather than re-rendering them ;)
I have already thought about that. But it will not be possible while developing a calendar view. Suppose I click a date of the next month, then the whole calendar body needs to be updated with the selected month's view.
@Raj Okay, if that's the approach, then it's currently fine as it is ;)
@Raj you can refer my answer for your requirement even though this answer is correct
1

When you are clicking on any element you are calling show() again so that DOM is getting created again and binding is getting cancelled So that you can bind to the document that ie if new DOM creates then it will automatically gets binded

    $(document).on("click", 'body #li-' + i, function(event){
         alert(i);
         this.show();
    }.bind(this));

2 Comments

Are you sure it will work? as far as I know, this won't automatically register the events.
Yes I tried it just now for cross verification. It's not recognizing the method (show()).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.