Search code examples
javascriptjqueryjquery-uijquery-ui-contextmenu

Using jQuery contextmenu to move items between lists - attach to new event after finished


I have 2 lists, A and B. I use A context menu (right click menu) which moves the item onto the other list but when I right click this item it is using its original data and classes. How do I achieve this?

Do I need to attach the item to the new list and how to do this?

When I right click in the task-head region then the menu is shown. If I pick an item in List A it is moved correctly and as expected to List B but if I now right click the same item in List B it shows 'Move to list B'. The console log seems to show that this item has updated but the result is wrong.

jQuery(document).ready(function($) {
  let menu = $('.context_menu');

  document.addEventListener("click", function(e) {
    if (e.target.closest('.context_menu'))
      return;
    menu.css('opacity', 0);
  });

  $(".a .task-head, .b .task-head").contextmenu(function(e) {
    e.preventDefault();
    let li = $(this).closest("li");
    console.debug(li);
    let id = li.data("id");
    let type = li.data("type");
    let html = "";
    if (type === "a") {
      html = "Move to List B";
    } else {
      html = "Move to List A";
    }
    alert(type);
    alert(html);

    $("#move").html(html).attr("data-id", id).attr("data-type", type);

    menu.css('position', 'absolute');
    menu.css('left', e.pageX + 'px');
    menu.css('top', e.pageY + 'px');
    menu.css('opacity', 1);
  });

  $("#move").click(function(e) {
    e.preventDefault();
    console.debug($(this));
    let id = $(this).data("id");
    let type = $(this).data("type");
    let date = $(this).data("date");
    let li = $('#' + type + '-' + id);

    if (type === "b") {
      li.removeClass("b");
      li.addClass("a");
      li.attr("data-type", "a");
      li.appendTo($("#list-a"));
      li.attr("data-id", id);
      li.attr('id', 'a-' + id);
      $('.context_menu').css('opacity', 0);
    } else if (type === "a") {
      li.removeClass("a");
      li.addClass("b");
      li.attr("data-type", "b");
      li.appendTo($("#list-b"));
      li.attr("data-id", id);
      li.attr('id', 'b-' + id);
      $('.context_menu').css('opacity', 0);
    }
  });
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css">
<script src="//code.jquery.com/jquery-3.6.0.js"></script>
<script src="//code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
<ol id="list-a">
  <li id="a-1" class="card a ui-front" data-type="a" data-id="1">
    <span class="task-head">Item 1</span>
    <div class="description">
      <p>This is item 1</p>
    </div>
  </li>
  <li id="a-2" class="card a ui-front" data-type="a" data-id="2">
    <span class="task-head">Item 2</span>
    <div class="description">
      <p>This is item 2</p>
    </div>
  </li>
</ol>
<ol id="list-b">
  <li id="b-3" class="card b ui-front" data-type="b" data-id="3">
    <span class="task-head">Item 3</span>
    <div class="description">
      <p>This is item 3</p>
    </div>
  </li>
  <li id="b-4" class="card b ui-front" data-type="a" data-id="4">
    <span class="task-head">Item 4</span>
    <div class="description">
      <p>This is item 4</p>
    </div>
  </li>
  <li id="b-5" class="card b ui-front" data-type="a" data-id="5">
    <span class="task-head">Item 5</span>
    <div class="description">
      <p>This is item 5</p>
    </div>
  </li>
</ol>
<div class="context_menu ui-front absolute mt-2 w-48 rounded-md shadow-lg origin-top-right right-0">
  <div class="rounded-md ring-1 ring-black ring-opacity-5 py-1 bg-white">
    <div id="context_menu_title" class="block px-4 py-2 text-xs text-gray-400">
      List Item Menu
    </div>
    <a id="move" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition" href="#" data-id="0" data-type="none">Move it!</a>
  </div>


Solution

  • The problem is this: let type = li.data("type");

    Yes it works the first time, but even when you update your data-type with a new value it will still get the original value. Use let type = li.attr("data-type");

    note, fix this multiple places

    Demo

    jQuery(document).ready(function($) {
      let menu = $('.context_menu');
    
      document.addEventListener("click", function(e) {
        if (e.target.closest('.context_menu'))
          return;
        menu.css('opacity', 0);
      });
    
      $(".a .task-head, .b .task-head").contextmenu(function(e) {
        e.preventDefault();
        let li = $(this).closest("li");
        console.debug(li);
        let id = li.data("id");
        let type = li.attr("data-type");
        let html = "";
        if (type == "a") {
          html = "Move to List B";
        } else {
          html = "Move to List A";
        }
    
        $("#move").html(html).attr("data-id", id).attr("data-type", type);
    
        menu.css('position', 'absolute');
        menu.css('left', e.pageX + 'px');
        menu.css('top', e.pageY + 'px');
        menu.css('opacity', 1);
      });
    
      $("#move").click(function(e) {
        e.preventDefault();
        let id = $(this).data("id");
        let type = $(this).attr("data-type");
        let date = $(this).data("date");
    
        let li = $('#' + type + '-' + id);
        if (type === "b") {
          li.removeClass("b");
          li.addClass("a");
          li.attr("data-type", "a");
          li.appendTo($("#list-a"));
          li.attr("data-id", id);
          li.attr('id', 'a-' + id);
    
          $('.context_menu').css('opacity', 0);
    
        } else if (type === "a") {
          li.removeClass("a");
          li.addClass("b");
          li.attr("data-type", "b");
          li.appendTo($("#list-b"));
          li.attr("data-id", id);
          li.attr('id', 'b-' + id);
          $('.context_menu').css('opacity', 0);
    
        }
    
      });
    
    });
    <!DOCTYPE html>
    <html class="light" lang="en">
    
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>list example</title>
      <link rel="stylesheet" href="/css/list.css">
      <link rel="stylesheet" href="//code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css">
      <script src="//code.jquery.com/jquery-3.6.0.js"></script>
      <script src="//code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
      <script src="/js/list.css"></script>
    </head>
    
    <body>
      <ol id="list-a">
        <li id="a-1" class="card a ui-front" data-type="a" data-id="1">
          <span class="task-head">Item 1</span>
          <div class="description">
            <p>This is item 1</p>
          </div>
        </li>
        <li id="a-2" class="card a ui-front" data-type="a" data-id="2">
          <span class="task-head">Item 2</span>
          <div class="description">
            <p>This is item 2</p>
          </div>
        </li>
      </ol>
      <ol id="list-b">
        <li id="b-3" class="card b ui-front" data-type="b" data-id="3">
          <span class="task-head">Item 3</span>
          <div class="description">
            <p>This is item 3</p>
          </div>
        </li>
        <li id="b-4" class="card b ui-front" data-type="a" data-id="4">
          <span class="task-head">Item 4</span>
          <div class="description">
            <p>This is item 4</p>
          </div>
        </li>
        <li id="b-5" class="card b ui-front" data-type="a" data-id="5">
          <span class="task-head">Item 5</span>
          <div class="description">
            <p>This is item 5</p>
          </div>
        </li>
      </ol>
      <div class="context_menu ui-front absolute mt-2 w-48 rounded-md shadow-lg origin-top-right right-0">
        <div class="rounded-md ring-1 ring-black ring-opacity-5 py-1 bg-white">
          <div id="context_menu_title" class="block px-4 py-2 text-xs text-gray-400">
            List Item Menu
          </div>
          <a id="move" class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition" href="#" data-id="0" data-type="none">
                    Move it!
                </a>
        </div>
    
    </body>
    
    </html>