简体   繁体   中英

HTML Select styled by jQuery with infinite loop

I have styled my select items using JQuery, which outputs the items in an unordered list. This is working. I've used some javascript to create in infinite scroll effect on the unordered list. The infinite scroll basically repeats the entire list resulting in two identical sets of list items. However, the cloned set list items are not clickable and thus the form does not render any results when clicking the cloned list items.

Link to the select in question (try the Emotional Quality Select) - http://dev.chrislamdesign.com/shortwave/sample-page/

Link to codepen infinite scroll - https://codepen.io/doctorlam/pen/oKgRvO

Here's my PHP

<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter">
    <div class="container d-flex justify-content-between">
        <div class="row" style="width: 100%">
    <?php
    if( $terms = get_terms( array('hide_empty' => false,'taxonomy' => 'emotional_quality', 'orderby' => 'name' ) ) ) : ?>
        <div id="emotional" class="col-md-4">
        <?php
            echo '<select class="form-submit" name="categoryfilter2"><option value="">Emotional Quality</option>';
            foreach ( $terms as $term ) :
                echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
            endforeach;
            echo '</select>'; ?>
        </div>
        <?php endif; 

        if( $terms = get_terms( array( 'hide_empty' => false,'taxonomy' => 'genre', 'orderby' => 'name' ) ) ) : ?>
            <div id="genre" class="col-md-4">

            <?php echo '<select class= "form-submit" name="categoryfilter"><option value="">Select genre...</option>';
            foreach ( $terms as $term ) :
                echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
            endforeach;
            echo '</select>'; ?>
        </div>
        <?php endif;

        if( $terms = get_terms( array( 'hide_empty' => false,'taxonomy' => 'cinematic_style', 'orderby' => 'name' ) ) ) : ?>
            <div id="cinematic" class="col-md-4">

            <?php echo '<select class="form-submit" name="categoryfilter3"><option value="">Cinematic Style</option>';
            foreach ( $terms as $term ) :
                echo '<option value="' . $term->term_id . '">' . $term->name . '</option>'; // ID of the category as the value of an option
            endforeach;
            echo '</select>'; ?>
        </div>
        <?php endif;



    ?>


    <!-- <button>Apply filter</button> -->
    <input type="hidden" name="action" value="myfilter">
</div><!-- row -->
</div>
</form>

Here's the Javascript to style the select

<script>
    jQuery(document).ready(function($){

    $('select').each(function(){
    var $this = $(this), numberOfOptions = $(this).children('option').length;

    $this.addClass('select-hidden'); 
    $this.wrap('<div class="select"></div>');
    $this.after('<div class="select-styled"></div>');

    var $styledSelect = $this.next('div.select-styled');
    $styledSelect.text($this.children('option').eq(0).text());

    var $list = $('<ul />', {
        'class': 'select-options'
    }).insertAfter($styledSelect);
    $list.wrap('<div class="scroll-container"><div class="wrap-container"></div></div>');
    for (var i = 0; i < numberOfOptions; i++) {
        $('<li />', {
            text: $this.children('option').eq(i).text(),
            rel: $this.children('option').eq(i).val()
        }).appendTo($list);
    }

    var $listItems = $list.children('li');

    $styledSelect.click(function(e) {
        e.stopPropagation();
        $('div.select-styled.active').not(this).each(function(){
            $(this).removeClass('active').next('.scroll-container').hide();
        });
        $(this).toggleClass('active').next('.scroll-container').toggle();
    });

    $listItems.click(function(e) {
        e.stopPropagation();
        $styledSelect.text($(this).text()).removeClass('active');
        $this.val($(this).attr('rel'));
        $('.scroll-container').hide();
        //console.log($this.val());
    });

    $(document).click(function() {
        $styledSelect.removeClass('active');
        $('.scroll-container').hide();
    });

});
    });
</script>

Here's the Javascript for the infinite scroll

<script>
    jQuery(function($){

$('#emotional .wrap-container').attr('id', 'wrap-scroll-1');
$('#emotional .wrap-container ul').attr('id', 'ul-scroll-1');

$('#genre .wrap-container').attr('id', 'wrap-scroll-2');
$('#genre .wrap-container ul').attr('id', 'ul-scroll-2');


$('#cinematic .wrap-container').attr('id', 'wrap-scroll-3');
$('#cinematic .wrap-container ul').attr('id', 'ul-scroll-3');


});
</script>

<!-- Infiinite scroll for emotional quality-->
<script>
var scrollW = document.getElementById("wrap-scroll-1");
var scrollUl = document.getElementById("ul-scroll-1");
var itemsScrolled,
  itemsMax,
  cloned = false;

var listOpts = {
  itemCount: null,
  itemHeight: null,
  items: []
};

function scrollWrap() {
    var scrollW = document.getElementById("wrap-scroll-1");
var scrollUl = document.getElementById("ul-scroll-1");
  itemsScrolled = Math.ceil(
    (this.scrollTop + listOpts.itemHeight / 2) / listOpts.itemHeight
  );

  if (this.scrollTop < 1) {
    itemsScrolled = 0;
  }

  listOpts.items.forEach(function(ele) {
    ele.classList.remove("active");
  });

  if (itemsScrolled < listOpts.items.length) {
    listOpts.items[itemsScrolled].classList.add("active");
  }

  if (itemsScrolled > listOpts.items.length - 3) {
    var node;
    for (_x = 0; _x <= itemsMax - 1; _x++) {
      node = listOpts.items[_x];

      if (!cloned) {
        node = listOpts.items[_x].cloneNode(true);
      }

      scrollUl.appendChild(node);
    }

    initItems(cloned);
    cloned = true;
    itemsScrolled = 0;
  }
}

function initItems(scrollSmooth) {
    var scrollUl = document.getElementById("ul-scroll-1");
    var scrollW = document.getElementById("wrap-scroll-1");


  listOpts.items = [].slice.call(scrollUl.querySelectorAll("li"));
  listOpts.itemHeight = listOpts.items[0].clientHeight;
  listOpts.itemCount = listOpts.items.length;

  if (!itemsMax) {
    itemsMax = listOpts.itemCount;
  }

  if (scrollSmooth) {
        var scrollW = document.getElementById("wrap-scroll-1");

    var seamLessScrollPoint = (itemsMax - 3) * listOpts.itemHeight;
    scrollW.scrollTop = seamLessScrollPoint;
  }
}

document.addEventListener("DOMContentLoaded", function(event) {
        var scrollW = document.getElementById("wrap-scroll-1");

  initItems();
  scrollW.onscroll = scrollWrap;
});


</script>

AJAX CALL

<script>
jQuery(function($){
    jQuery('.select-options li').click(function() {
        var filter = $('#filter');
        $.ajax({
            url:filter.attr('action'),
            data:filter.serialize(), // form data
            type:filter.attr('method'), // POST
            beforeSend:function(xhr){
                filter.find('button').text('Processing...'); // changing the button label
            },
            success:function(data){
                filter.find('button').text('Apply filter'); // changing the button label back
                $('#response').html(data); // insert data
            }
        });
        return false;
    });
});
</script>

The original list items trigger the form and return the correct results. The cloned list items don't. I think it has to do with the identical rel values but am not sure.

Changing your ajax call to the below suggested way should make the click work for you:

<script>
    jQuery(function($){
        jQuery('body').on('click', '.select-options li', function() {
            var filter = $('#filter');
            $.ajax({
                url:filter.attr('action'),
                data:filter.serialize(), // form data
                type:filter.attr('method'), // POST
                beforeSend:function(xhr){
                    filter.find('button').text('Processing...'); // changing the button label
                },
                success:function(data){
                    filter.find('button').text('Apply filter'); // changing the button label back
                    $('#response').html(data); // insert data
                }
            });
            return false;
        });
    });
</script>

The reason as to why this should work is because now the click event is bound on the class irrespective of whether the element with that class was loaded in DOM loading or after the DOM was loaded completely.

The direct call to .click or in the format jQuery('.select-options li').on('click', function(){}); only binds event to elements loaded before the DOM was ready.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM