0

I have the following code that dynamically creates an environment over a page. The ultimate goal is to create a "walk-through wizard" for users.

This code adds an overlay over my page, and then a container with a next and previous button in it.

Then, using Ajax, I populate the container for each step (triggered by the Next/Prev buttons).

In order to achieve some unique styles and apply unique functions to each step, I add a class to the container and to the buttons for each step. For example, The first step, the container has the class step1, as do the buttons, second step has the class step2 applied to the container and buttons and so on.

What I'm finding is that I can't apply functions to buttons based on the class that changes using jQuery.

For example, here is my code that creates the environment, calls the files for each step and adds all the classes:

jQuery(function ($) {
  $('body').attr('onboarding_step', 'step1');
  $('body.wp-customizer').addClass('skizzar_onboarding');
  $('<div id="so_overlay"></div>').insertBefore('body.wp-customizer');

// first step
  $('#so_overlay').html('<div id="onboarding_steps_container" class="step1"></div>');
  $('#onboarding_steps_container').html('<div class="onboarding_steps"></div><div class="button_holder"><button id="prev" class="step1"><i class="fa fa-chevron-left"></i> PREV</button><button id="next" class="step1">NEXT <i class="fa fa-chevron-right"></i></button></div>');

// here's the steps
var steps = [
  "wp-content/plugins/skizzar-onboarding/ajax/step1.php",
  "wp-content/plugins/skizzar-onboarding/ajax/step2.php",
  "wp-content/plugins/skizzar-onboarding/ajax/step3.php",
  "wp-content/plugins/skizzar-onboarding/ajax/step4.php",
  "wp-content/plugins/skizzar-onboarding/ajax/step5.php",
];
counter = 0;
$('.onboarding_steps').load(steps[counter]);

$('#next').click(function () {
  counter = (counter + 1) % steps.length; 
  $('.onboarding_steps').load(steps[counter]); 
  $('#onboarding_steps_container, .button_holder button, #so_overlay').attr('class', 'step' + (counter + 1)); 
  $('body').attr('onboarding_step', 'step' + (counter + 1)); 
});

$('#prev').click(function () {
  counter = (counter - 1) % steps.length; 
  $('.onboarding_steps').load(steps[counter]); 
  $('#onboarding_steps_container, .button_holder button, #so_overlay').attr('class', 'step' + (counter + 1)); 
  $('body').attr('onboarding_step', 'step' + (counter + 1)); 
});

});

Now if I were to add the follownig code to send a message to the console when the button with class .step2 is pressed:

$('.step2 #next').click(function () {
    console.log('step 2 pressed');
});

Nothing happens. I think this is because I am changing the class via jQuery, however, I have no idea how to get around this problem.

Here is a jsfiddle showing my issue: https://jsfiddle.net/dkzjpnbo/3/

(Obviously I can't load the files using jsfiddle, but if you inspect the elements, you will see that second time you press NEXT (which has the class step2 it should send an alert, but it does nothing)

Sam Skirrow
  • 3,647
  • 15
  • 54
  • 101
  • You need to use a delegated event handler. See the question I marked as duplicate for more details. – Rory McCrossan Jan 29 '16 at 13:31
  • @RoryMcCrossan - I see. I have added what I believe to be right based on that question, but now it's returning something in the console every time I press the button, regardless of what the dynamic class is $(document).on('click', '.step2 #next', function() { console.log('step 2 pressed'); }); https://jsfiddle.net/dkzjpnbo/7/ – Sam Skirrow Jan 29 '16 at 13:35
  • actually, forget that, I changed my selector and it seems to work. however, now it shows the message in the console WHEN the class changes to step2 - not when I click the button – Sam Skirrow Jan 29 '16 at 13:37

1 Answers1

0

This is because when you add an event like this

$('.step2 #next').click(function () {
    console.log('step 2 pressed');
});

your code won't handle dynamically added content. If you change classes, add new tags with that class or anything like that, it will not work. Even so, you can simply use the $("#next") selector since you use an id, and an id should always be unique.

The solution is to add the even with the on method, like this, over a wrapper container. For example, add a div <div id='wrapper'></div> in the begining and append content with jQuery to it.

$('#wrapper').on("click", ".step2 #next", function () {
    console.log('step 2 pressed');
});
Simply Me
  • 1,579
  • 11
  • 23
  • This won't fix the issue. The use of `on()` by itself won't handle dynamic content. The two code snippets you have are logically identical. – Rory McCrossan Jan 29 '16 at 13:27
  • @RoryMcCrossan is correct, see my updated fiddle - https://jsfiddle.net/dkzjpnbo/6/ still not working, even when changing to on – Sam Skirrow Jan 29 '16 at 13:30
  • This will probably help though:- $('.step2').on("click", "#next", function () { console.log('step 2 pressed'); }); Calling the click id after parent element. – Jamie Paterson Jan 29 '16 at 13:40
  • @RoryMcCrossan, you are right, forgot the middle parameter. Updated my answer. I used something like this for a webpage generated fully with jQuery and this worked. (as it is now, not as it was). – Simply Me Jan 29 '16 at 13:43