1

I've succeeded in implementing most of the desired functionality via this JavaScript but there is still a potentially troublesome bug that I can't figure out: the code I wrote appends desired HTML but creates unnecessary duplicates.

The Problem

The code appends the button multiple times, when it should append just once. How do I stop the multiples?

The (li)st items show up in a ul styled like a table like this (the numbering is arbitrary and I only use it for our reference):

| 1 | 2 |
| 3 | 4 |
| 5 | 6 |

  • It gives listing 4, 1 buttons
  • It gives listing 1, 2 buttons
  • It gives listing 2, 3 buttons

Is it going right-to-left top-to-bottom? And if so, why?


What I tried to accomplish:

Stage 1 - Check for video and add button if video present

  1. Check product listings on this category page to see if any have ".Options"
  2. If they have .Options, check to see if a video matching this product's ID exists in /Videos/ folder
  3. If video with matching Product ID exists in videos folder, attach a Play/Stop toggle button to product listing

Stage 2 - Play/Stop video on button press

  1. If Play/Stop button is pressed, add tag with relevant video URL
  2. If video is playing, stop and hide video upon button press

The JavaScript

    $('.videoDemoBtn').on('click', function () {
    if ($(this).hasClass('videoPlaying')) {
        $(this).removeClass('videoPlaying');
        $(this).parent().find('div.categoryDemoVideo').hide().html('');
        }
        else {
            var ProductId = $(this).parent().find('div.ProductImage').attr('data-product');
            $(this).addClass('videoPlaying');
            $(this).parent().find('div.categoryDemoVideo').show().html('<video id="demoVideo" class="video" preload="auto" autoplay="autoplay" loop="loop" autobuffer="autobuffer" muted="muted" controls="controls" width="100%" height="100%" poster="https://store-mixi7d.mybigcommerce.com/content/videos/'+ProductId+'.jpg"><source src="https://store-mixi7d.mybigcommerce.com/content/videos/'+ProductId+'.mp4"><source src="https://store-mixi7d.mybigcommerce.com/content/videos/'+ProductId+'.ogv" type="video/ogg"><p>Your browser does not support this video.  Please upgrade your browser!</p></video>');
                    }
            });
    $(".Options").each(function checkForVideo(url) {
    var ProductCatOpt = $(this);
        ProductId = $(this).parent().parent().find('div.ProductImage').attr('data-product');
    function ajax1() {
        return $.ajax('/content/videos/'+ProductId+'.mp4')
            .done(function() { 
                $(ProductCatOpt).addClass('withVideo');
            }).fail(function() { 
                return;
            });
        }
        $.when(ajax1()).done(function(a1){
            $('.withVideo').closest('li').append('<span class="videoDemoBtn"><div class="triangle"></div></span>');
       });
    });

The HTML

    <ul class="ProductList " style="position: relative; height: 1407px;">
        <li class="Odd " style="min-height: 456px; position: absolute; left: 0px; top: 0px;">
            <div class="ProductImage QuickView" data-product="296"> 
                <div class="categoryDemoVideo"></div>
            </div>
            <div class="ProductActionAdd" style="display:;"> 

                <a href="#someproduct" class="btn Small icon-Choose Options withVideo" title="Choose Options">Choose Options</a></div>

            <!-- Here in the first listing in the ul with class .Options it creates 2 buttons -->               
            <span class="videoDemoBtn"><div class="triangle"></div></span>
            <span class="videoDemoBtn"><div class="triangle"></div></span>
            <!-- Here in the first listing in the ul with class .Options it creates 2 buttons -->               

        </li>
        <li class="Even " style="min-height: 456px; position: absolute; left: 310px; top: 0px;">
            <div class="ProductImage QuickView" data-product="431"> 
                <div class="categoryDemoVideo"></div>
            </div>
            <div class="ProductActionAdd" style="display:;"> 

                <a href="#someproduct" class="btn Small icon-Choose Options withVideo" title="Choose Options">Choose Options</a></div>

            <!-- While here in the 2nd to last listing in the ul with class .Options it creates 3 buttons -->               
           <span class="videoDemoBtn"><div class="triangle"></div></span>
           <span class="videoDemoBtn"><div class="triangle"></div></span>
           <span class="videoDemoBtn"><div class="triangle"></div></span>
            <!-- While here in the 2nd to last listing in the ul with class .Options it creates 3 buttons -->               

        </li>
        <li class="Odd " style="min-height: 435px; position: absolute; left: 0px; top: 476px;">
            <div class="ProductImage QuickView" data-product="389">         
                <div class="categoryDemoVideo"></div>
            </div>
            <div class="ProductActionAdd" style="display:;"> 
                <a href="#someproduct" class="btn Small icon-Add To Cart" title="Add To Cart">Add To Cart</a></div>
        </li>
        <li class="Even " style="min-height: 435px; position: absolute; left: 310px; top: 476px;">
            <div class="ProductImage QuickView" data-product="393"> 
                <div class="categoryDemoVideo"></div>
            </div>
            <div class="ProductActionAdd" style="display:;"> 

                <a href="#someproduct" class="btn Small icon-Choose Options withVideo" title="Choose Options">Choose Options</a></div>

            <!-- And yet ere in the last listing in the ul with class .Options it creates just 1 button -->               
            <span class="videoDemoBtn"><div class="triangle"></div></span>
            <!-- And yet ere in the last listing in the ul with class .Options it creates just 1 button -->               

       </li>
        <li class="Odd " style="min-height: 456px; position: absolute; left: 0px; top: 931px;">
            <div class="ProductImage QuickView" data-product="428"> 
                <div class="categoryDemoVideo"></div>
            </div>
            <div class="ProductActionAdd" style="display:;"> 
                <a href="#someproduct" class="btn Small icon-Add To Cart" title="Add To Cart">Add To Cart</a></div>
        </li>
        <li class="Even " style="min-height: 456px; position: absolute; left: 310px; top: 931px;">
            <div class="ProductImage QuickView" data-product="388">         
                <div class="categoryDemoVideo"></div>
            </div>
            <div class="ProductActionAdd" style="display:;"> 
                <a href="#someproduct" class="btn Small icon-Add To Cart" title="Add To Cart">Add To Cart</a></div>
        </li>
    </ul>

I've done a JSFiddle here but it's of no help as the videos that must be checked for with ajax have to be on same domain for this to work, and the ProductIDs are dynamically generated by the PHP of the platform I am using.

I am specifically looking to stop the behavior that causes multiple buttons to be appended instead of just 1, however, I wouldn't be surprised if my code was sloppy and inefficient so please feel free to criticize any part of this.

Andre Bulatov
  • 1,090
  • 3
  • 16
  • 47

2 Answers2

2

Every time you get an AJAX response, you're adding another click handler to all the .videoDemoBtn elements. So the next time you click on one of them, it will run the handler multiple times, which adds multiple copies of the HTML.

You should do all your event binding at top-level. Since these are dynamically-added elements, you should use event delegation, as described in

Event binding on dynamically created elements?

Community
  • 1
  • 1
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Just so I understand correctly: 1. Use on() instead of click due to dynamically added event handled .videoDemoBtn 2. Put $('.videoDemoBtn').on() { ... before the ajax function. Is that correct? Also, when do I mark your answer as correct? Since I am ignorant in this area, do I try your answer first, then report/mark? – Andre Bulatov Dec 27 '14 at 20:20
  • Yes, I think you understand correctly. You should mark it correct when you think you've been able to make use of the answer correctly. If you encounter a problem, you can post your attempt as an addition to the question, and I'll try to help you apply the solution. – Barmar Dec 27 '14 at 20:22
  • Great thank you. I updated the code at the bottom of question to have the event handler come before the ajax call and also the event handler was changed from 'click' to 'on()', but I still get the same result, except now, the videoDemoBtn also no longer triggers video. Before, I suspected the answer and though I didn't have a solution, I figured it would be something along the lines of your answer. Now, I have no idea why this is not working, particularly the button trigger event... Any ideas? – Andre Bulatov Dec 27 '14 at 20:50
1

To handle dynamic elements you need to bind to a pre-existing element and delegate the event handling to that.

Change

$('.videoDemoBtn').on('click', function () {

to

$('.ProductList').on('click', '.videoDemoBtn', function () {

[Update]

For the issue with the duplicate buttons you most likely need to change

$('.withVideo').closest('li').append('<span class="videoDemoBtn"><div class="triangle"></div></span>');

to

ProductCatOpt.closest('li').append('<span class="videoDemoBtn"><div class="triangle"></div></span>');

this way you only append the element to the relevant product instead of all the .withVideo elements in the page.

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
  • That's excellent, I appreciate that, it fixes the event handlers, and now the buttons work again. However, I am still having the original multiple buttons problem even when I apply the code from @Barmar's answer and properly delegate the event as you describe here. Also, the multiple are created on load, no on click. Clicking them doesn't create extras, that was never a problem. I would upvote for a useful contribution but alas, I cannot. – Andre Bulatov Dec 30 '14 at 21:07
  • 1
    @AndreBulatov updated answer with what i believe to be the problem. – Gabriele Petrioli Dec 30 '14 at 23:29
  • Thank you so much, both parts of the answer work perfectly and I've learned a lot about event delegation and selection. It seems so obvious in hindsight -- 1. add class, 2. add button to all ele with class (1), 3. add class, 4. add button to all ele with class (11 1), 5. add class, 6. add button to all ele with class (111 11 1) - doh! Again, thank you. – Andre Bulatov Dec 31 '14 at 22:52