1

I have prepared a jsfiddle for my problem.

I define a custom jQuery UI widget representing a game table with up to 4 players and a white gid ("game id") number in the middle:

screenshot

Here is my code (same as in the jsfiddle):

$(function() {
  var PHOTO_PATTERN = /^https:\/\/\S+/i;

  $.widget('raspasy.table', {
    // default options
    options: {
      gid: NaN,
      player0: null,
      player1: null,
      player2: null,
      player3: null
    },

    _create: function() {
      this.element.addClass('raspasy-table');

      this.gidDiv = $('<div/>', {
        'class': 'raspasy-table-gid'
      }).appendTo(this.element);
      this.player0 = $('<div/>', {
        'class': 'raspasy-table-player0'
      }).appendTo(this.element);
      this.player1 = $('<div/>', {
        'class': 'raspasy-table-player1'
      }).appendTo(this.element);
      this.player2 = $('<div/>', {
        'class': 'raspasy-table-player2'
      }).appendTo(this.element);
      this.player3 = $('<div/>', {
        'class': 'raspasy-table-player3'
      }).appendTo(this.element);

      this.rep0 = $('<div/>', {
        'class': 'raspasy-player-rep'
      }).appendTo(this.player0);
      this.bad0 = $('<div/>', {
        'class': 'raspasy-player-bad-small'
      }).appendTo(this.rep0);
      this.good0 = $('<div/>', {
        'class': 'raspasy-player-good-small'
      }).appendTo(this.rep0);

      this.rep1 = $('<div/>', {
        'class': 'raspasy-player-rep'
      }).appendTo(this.player1);
      this.bad1 = $('<div/>', {
        'class': 'raspasy-player-bad-small'
      }).appendTo(this.rep1);
      this.good1 = $('<div/>', {
        'class': 'raspasy-player-good-small'
      }).appendTo(this.rep1);

      this.rep2 = $('<div/>', {
        'class': 'raspasy-player-rep'
      }).appendTo(this.player2);
      this.bad2 = $('<div/>', {
        'class': 'raspasy-player-bad-small'
      }).appendTo(this.rep2);
      this.good2 = $('<div/>', {
        'class': 'raspasy-player-good-small'
      }).appendTo(this.rep2);

      this.rep3 = $('<div/>', {
        'class': 'raspasy-player-rep'
      }).appendTo(this.player3);
      this.bad3 = $('<div/>', {
        'class': 'raspasy-player-bad-small'
      }).appendTo(this.rep3);
      this.good3 = $('<div/>', {
        'class': 'raspasy-player-good-small'
      }).appendTo(this.rep3);

      this._refresh();
    },

    _destroy: function() {

      this.good0.remove();
      this.bad0.remove();
      this.rep0.remove();

      this.good1.remove();
      this.bad1.remove();
      this.rep1.remove();

      this.good2.remove();
      this.bad2.remove();
      this.rep2.remove();

      this.good3.remove();
      this.bad3.remove();
      this.rep3.remove();

      this.player0.remove();
      this.player1.remove();
      this.player2.remove();
      this.player3.remove();

      this.gidDiv.remove();

      this.element.removeClass('raspasy-table');
    },

    _setOptions: function() {
      this._superApply(arguments);
      this._refresh();
    },

    _drawPerson: function(playerDiv, badDiv, goodDiv, playerJson) {
      if (playerJson) {
        var photo = (PHOTO_PATTERN.test(playerJson.photo) ? playerJson.photo : 'https://raspasy.de/raspasy/images/male_happy.png');
        playerDiv.css('background-image', 'url("' + photo + '")');
        var rep = parseFloat(playerJson.rep);
        if (0 <= rep && rep <= 1) {
          var w = badDiv.width();
          badDiv.height(w * (1 - rep)).show();
          goodDiv.height(w * rep).show();
        } else {
          badDiv.hide();
          goodDiv.hide();
        }
        playerDiv.show();
      } else {
        playerDiv.hide();
      }
    },

    _refresh: function() {
      this.gidDiv.text('#' + this.options.gid);

      this._drawPerson(this.player0, this.bad0, this.good0, this.options.player0);
      this._drawPerson(this.player1, this.bad1, this.good1, this.options.player1);
      this._drawPerson(this.player2, this.bad2, this.good2, this.options.player2);
      this._drawPerson(this.player3, this.bad3, this.good3, this.options.player3);

      this.player0.css('transform', 'rotate(' + (4 - 8 * Math.random()) + 'deg)');
      this.player1.css('transform', 'rotate(' + (4 - 8 * Math.random()) + 'deg)');
      this.player2.css('transform', 'rotate(' + (4 - 8 * Math.random()) + 'deg)');
      this.player3.css('transform', 'rotate(' + (4 - 8 * Math.random()) + 'deg)');
    }
  });

  // MAIN SCRIPT

  var tablesList = $('#tablesList').selectable();
  var table1 = $('<li/>').appendTo(tablesList).table({
    gid: 3
  });
  var table2 = $('<li/>').appendTo(tablesList).table({
    gid: 104,
    player0: {
      rep: Math.random()
    }
  });
  var table3 = $('<li/>').appendTo(tablesList).table({
    gid: 115,
    player0: {
      rep: Math.random()
    },
    player1: {},
    player2: {
      rep: Math.random(),
      photo: 'https://raspasy.de/raspasy/images/male_sad.png'
    },
    player3: {
      rep: Math.random(),
      photo: 'https://raspasy.de/raspasy/images/female_happy.png'
    }
  });
  var table4 = $('<li/>').appendTo(tablesList).table({
    gid: 116,
    player0: {
      photo: 'https://raspasy.de/raspasy/images/female_happy.png'
    },
    player1: {
      rep: Math.random(),
      photo: 'https://raspasy.de/raspasy/images/female_sad.png'
    },
    player2: {
      rep: Math.random(),
      photo: 'https://raspasy.de/raspasy/images/male_sad.png'
    },
    player3: {
      rep: Math.random(),
      photo: 'https://raspasy.de/raspasy/images/female_happy.png'
    }
  });

  table1.click(function() {
    console.log('table clicked: ' + this.gid);
    alert('table clicked: ' + this.gid);
  });
  table2.click(function() {
    console.log('table clicked: ' + this.gid);
    alert('table clicked: ' + this.gid);
  });
  table3.click(function() {
    console.log('table clicked: ' + this.gid);
    alert('table clicked: ' + this.gid);
  });
  table4.click(function() {
    console.log('table clicked: ' + this.gid);
    alert('table clicked: ' + this.gid);
  });

});
.raspasy-table {
  position: relative;
  background: #A3DD8E;
  color: white;
  margin: 50px;
  float: left;
  border: 4px solid #91BCE5;
  border-radius: 16px;
  box-shadow: 0 0 32px rgba(0, 0, 0, 0.2);
  width: 160px;
  height: 160px;
}

.raspasy-table:hover {
  background-color: #92CC7D;
}

.raspasy-table-gid {
  position: absolute;
  font-size: 1.5em;
  top: 65px;
  width: 100%;
  color: white;
  text-align: center;
}

.raspasy-table-player0 {
  position: absolute;
  left: -40px;
  top: 50px;
  background: #FFF no-repeat center;
  background-size: contain;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
  width: 80px;
  height: 60px;
  display: none;
}

.raspasy-table-player1 {
  position: absolute;
  left: 40px;
  top: -30px;
  background: #FFF no-repeat center;
  background-size: contain;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
  width: 80px;
  height: 60px;
  display: none;
}

.raspasy-table-player2 {
  position: absolute;
  left: 120px;
  top: 50px;
  background: #FFF no-repeat center;
  background-size: contain;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
  width: 80px;
  height: 60px;
  display: none;
}

.raspasy-table-player3 {
  position: absolute;
  left: 40px;
  top: 130px;
  background: #FFF no-repeat center;
  background-size: contain;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
  width: 80px;
  height: 60px;
  display: none;
}
<ul id="tablesList"></ul>

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> 
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

My problem is that the click is not working.

I have also tried:

table1.on('click', function (event, ui) {
  console.log('table clicked: ' + this.gid);
  alert('table clicked: ' + this.gid);
});

And:

table1._on( this.element, {
    'click': function( event ) {
        event.preventDefault();
        console.log('table clicked: ' + this.gid);
        alert('table clicked: ' + this.gid);
    }
});

but still the click handler code is not called.

UPDATE:

I have tried adding the suggestion by Twisty (thank you!), which works perfectly in his jsfiddle:

  $("#tablesList").on("click", ".raspasy-table", function() {
    var myID = $(this).table("option", "gid");
    console.log('table clicked: ' + myID);
    alert('table clicked: ' + myID);
  });

but in my real app it is not working.

Is the click event maybe masked by $('#tablesList').selectable(); line in my code?

When I inspect the #tablesList element it seems to have 2 event handlers. Is the first handler stealing the click event from the second one?

game screenshot

6
  • In your jsfiddle, do you see this Chrome Developer tool error in the console? Uncaught ReferenceError: table1 is not defined at ?editor_console=:378 Commented Oct 30, 2020 at 20:28
  • I think it's a scope issue. Commented Oct 30, 2020 at 20:36
  • If you remove the code below // MAIN SCRIPT then errors disappear. So I think my question is still valid: how to add a click handler to each table widget and use the gid in the handler? Commented Oct 30, 2020 at 20:36
  • Did you just fix it? I looked your code was outside of the document.ready function or $(function() Commented Oct 30, 2020 at 20:41
  • 1
    Since the gid is a part of the options, you can read it from the getter: $(this).table("option", "gid"); Commented Oct 30, 2020 at 20:48

1 Answer 1

1

To address this, you will want to use an .on() for click and also call the gid via the Getter.

Example: https://jsfiddle.net/Twisty/6bmtnL1f/7/

JavaScript

  $("#tablesList").on("click", ".raspasy-table", function() {
    var myID = $(this).table("option", "gid");
    console.log('table clicked: ' + myID);
    alert('table clicked: ' + myID);
  });

I would advise moving this into the _create function. To do this, you add the .click() after the table has been created.

Example: https://jsfiddle.net/Twisty/6bmtnL1f/16/

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

2 Comments

Thank you for the great answer (as always by you). Could you please take a look at the updated question? If I have the $('#tablesList').selectable(); then the click handler is not called.
@AlexanderFarber Selectable should not interfere, it just adds a Class to the items selected. IF you're seeing two event handlers, maybe one cannot bubble up over the other. I would suggest investigating or opening a new question.

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.