3

I recently started playing around with javascript for fun. I worked myself through the most of w3schools tutorial (including jquery ofc).

The point where i got stuck is simply calling a function at a click of a button.

My code (edited to provide a Minimal, Complete, and Verifiable example)

$("#linkId1").on("click", function(){

  setTimeout(function(){

  function decryptText() {
  alert( "decrypted!" );
  }

  $("tableId").append('<a id="decryptID" class="button">decrypt</a>');
  $("#decryptID").on("click", decryptText);

  }, 500);
});

HTML:

<a id="linkId1">firstLink</a>

<table>
 <tbody>
  <tr>
   <td id="tableId">
    <a id="button1" class="button"></a>
    <a id="button2" class="button"></a>
   </td>
  </tr>
 </tbody>
</table>

Here's what i've already tried:

  • Different approaches to calling the function
  • Making the function decryptText() global or local

  • - Adding an eventListener to the button after creating it (because I read on another post that it's better to use the eventListener than putting the onclick attribute in the HTML-tag). ~I mixed basic js with jQuery methods here - BIG mistake.

The browser console does not give me any errors - when I changed to code a bit, I got: Reference Error: decryptText() not defined

S.

EDIT: I tried doing it all in jQuery only, the selectors and the event handling.

As you can see, I changed the example code to the beginning of a simple encrypt and decrypt script - the core problem still stays the same though.

Checking with Firefox' inspector tool, this time the element does not have any event bound to it.

A probably important piece of information is that the table you can see in the HTML does not exist before an onclick ajax handler is called from the element #linkId1 and inserts the whole div containing the tables into the html.

Sonorius
  • 53
  • 5
  • 5
    You should not be mixing so many different “styles” to begin with (addEventListener, onclick attribute, jQuery is also in the mix) ... since you are using jQuery already, I would recommend that you stick to its event handling. _“The point where i got stuck is simply calling a function at a click of a button”_ - is it really? If you just wanted to call a function on a button click, why are there multiple setTimeouts in your code, what are those supposed to achieve? – CBroe Aug 29 '17 at 11:43
  • In general, when you use “old school” event handling via HTML attributes, the function must exist before the parser encounters the element. You’re adding a level of complexity here by dynamically generating and inserting the element, not sure how that might play into it. But if you need any further help analyzing this, then please first of all provide a [mcve]. – CBroe Aug 29 '17 at 11:45
  • also add relevant html here. – Maulik Aug 29 '17 at 11:49
  • Thank you, I will try to stay with one style! Well the reason there are timeouts in the code is because the window I am currently trying to customize opens when I click a link - until then, it stays hidden. I know this is really bad/amateur coding, but this little workaround did the trick for the time being - at least until I find the time to look into that problem. But at the moment, calling functions on button clicks is my main concern :) – Sonorius Aug 29 '17 at 11:50
  • The minimal, complete and verifiable example is really hard to do, but I will try my best recreating my problem on a smaller scale. Also, I will put the mentioned html part in there. – Sonorius Aug 29 '17 at 11:56
  • Also, don't use w3fools.com – user234461 Aug 29 '17 at 12:17
  • 1
    are you trying to achieve, if button click, append a row into the table, and add a click event for the hyperlink with the id as decryptID? so that you can click it to run another function? if yes, 1st, don't set a static id in your dynamic generated hyperlink, switch it to class, remove the id, or generate the id dynamically – Se0ng11 Aug 30 '17 at 08:30
  • That was exactly my intention. After klicking the first link, add button nr. 3 to the two existing buttons, and run the specified function after I click it. I just tried changing the class - and it worked. The problem now is, that I can't change the class of the hyperlink due to its css styling (button) - how would I create a dynamic id for the hyper element? – Sonorius Aug 30 '17 at 08:43
  • I removed the class and changed the selector in the on() statement. – Sonorius Aug 30 '17 at 08:50
  • the second thing is why there is tr td but no table? tr td wont survive without table, did u miss anything here? – Se0ng11 Aug 30 '17 at 08:53
  • no there definitely is a table, I just forgot to put it into the HTML :/ – Sonorius Aug 30 '17 at 08:55
  • you mentioned clickFirst, what does clickFirst function do? – sanjiv saini Aug 30 '17 at 08:56
  • Oh I changed to code to a smaller example of my problem - I will edit that out for future reference. – Sonorius Aug 30 '17 at 09:00

3 Answers3

2

I solved it! (Thanks to Cbroe & Se0ng11)

Code before:

$("#tableId").append('<a id="decryptID" class="button">decrypt</a>');
$("#decryptID").on("click", decryptText);

Code after:

$("#tableId").append('<a class="button">decrypt</a>');
$(".button:contains('decrypt')").on("click", decryptText);

The problem was created by the static ID i assigned to the hyperlink element I append() in line 1. Removing the ID and changing the jQuery selector in line 2 worked!

Sonorius
  • 53
  • 5
1

I'm going to provide an alternative solution to your problem. If you create the element as a fully fledged jQuery before you append it to the table you can bind the click event directly to this without having to find it again:

var newA = $('<a\>').addClass('button').text('decrypt');
newA.on("click", decryptText);
$("#tableId").append(newA);

$('<a\>') will create the DOM element as a variable before you append it to the DOM. The main advantage here over your current code is this will guarantee that that click is bound to that <a> tag, even if you have multiple elements with the same text(decrypt). I'm mainly saying this becuase the selector you use ".button:contains('decrypt')" is pretty vague and could match things that your not expecting or event bind a handler twice if you run the same code twice.

Another option is to bubble the events using delegation:

$("#tableId").on('click', '.button', decryptText);

the event handler is now bound to the static item tableId but it's listening for events that match the underlying class button. This is covered comprehensibly here Event binding on dynamically created elements?

With the above you can happily add as many new <a> as you want safe in the knowledge that the event binding is already dealt with, i.e. you don't have to bind the event on creation.

Liam
  • 27,717
  • 28
  • 128
  • 190
-1

Try this, you was missing few things, $(document).ready(function () {} and $("tableId").append(...); should be using # $("#tableId").append(...); because tableId is id of the element not element itself. It will work with W3c as well it is not like you should not use this or that because of you are beginner. you can use any where.

$(document).ready(function () {
         $("#linkId1").on("click", function () {
         setTimeout(function () {
         function decryptText() {alert("decrypted!");
         }
         $("#tableId").append('<a id="decryptID" class="button">decrypt</a>');
         $("#decryptID").on("click", decryptText);}, 500);});
         });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table><tr><td>
      <a id="linkId1">firstLink</a></td>
    </tr>
        <tr><td id="tableId">
            <a id="button1" class="button"></a>
            <a id="button2" class="button"></a>
            </td>
        </tr>
 </table>
Liam
  • 27,717
  • 28
  • 128
  • 190
Bhanu Pratap
  • 1,635
  • 17
  • 17
  • this might work, but it's wrong, on many levels. Also please read [How do I format my posts using Markdown or HTML?](https://stackoverflow.com/help/formatting) As discussed in the comments, what's the `setTimeout` doing? – Liam Aug 30 '17 at 09:31