Как отфильтровать результаты в jQuery с несколькими вариантами выбора, включая диапазон дат? - PullRequest
1 голос
/ 02 октября 2019

Я пытаюсь отфильтровать результаты по атрибутам данных. По большей части я думаю, что я там (это работает на первых 3 селекторах), но у меня возникают проблемы, пытаясь включить селектор даты в уравнение. На данный момент я сомневаюсь, что мой подход в целом верен - я могу изменить HTML, если требуется, поэтому не стесняйтесь предлагать лучшее решение.

Для удобства всех, кто готов помочь, вот скрипка: https://jsfiddle.net/rnbx0c3j/

СПАСИБО

Селекторы:

<div id="stats_filter">
    <div id="stats_filter_wrapper" class="grids">
        <div class="grid-3 select-wrapper server first">
            <label class="server">Server</label>
            <select id="select-server">
                <option value="all">All</option>
                <option value="NicNicFunGame">NicNicFunGame</option>
                <option value="GT3_races">GT3_races</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper track">
            <label class="track">Track</label>
            <select id="select-track">
                <option value="all">All</option>
                <option value="ks_brands_hatch">ks_brands_hatch</option>
                <option value="Imola">Imola</option>
                <option value="Spa">Spa</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper car">
            <label class="car">Car</label>
            <select id="select-car">
                <option value="all">All</option>
                <option value="ariel_atom_v8">ariel_atom_v8</option>
                <option value="rr_caterham_academy_620r">rr_caterham_academy_620r</option>
                <option value="ks_porsche_911_gt1">ks_porsche_911_gt1</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper date">
            <label class="date">Date</label>
            <select id="select-date">
                <option value="all">All</option>
                <option value="7">Last 7 days</option>
                <option value="30">Last 30 days</option>
                <option value="182">Last 6 months</option>
                <option value="365">Last 12 months</option>
            </select>
        </div>
    </div>
</div>

HTML для фильтрации

<div class="stats-section" id="sectionID_1" data-server="NicNicFunGame" data-track="ks_brands_hatch" data-date="27/09/2019" data-car="ariel_atom_v8">sectionID_1</div>
<div class="stats-section" id="sectionID_2" data-server="NicNicFunGame" data-track="Imola" data-date="03/07/2019" data-car="rr_caterham_academy_620r">sectionID_2</div>
<div class="stats-section" id="sectionID_3" data-server="GT3_races" data-track="Spa" data-date="14/01/2019" data-car="ariel_atom_v8, ks_porsche_911_gt1">sectionID_3</div>

JS

var $select = $('#stats_filter select');
var $statsSection = $('.stats-section');

$select.change(function () {
    var include = '';
    var exclude = [];
    var showAll = true;
    var filterDate = false;

    $select.each(function () {
        var val = $(this).children(':selected').val();

        if (val !== 'all') {

            switch ($(this).prop('id')) {
                case 'select-server':
                    include += "[data-server='" + val + "']";
                    break;
                case 'select-track':
                    include += "[data-track='" + val + "']";
                    break;
                case 'select-car':
                    include += "[data-car*='" + val + "']";
                    break;
                case 'select-date':
                    var selectedDate = new Date(new Date().setDate(new Date().getDate() - val));
                    var dd = selectedDate.getDate();
                    var mm = selectedDate.getMonth() + 1;
                    var yyyy = selectedDate.getFullYear();
                    if (dd < 10) {
                        dd = '0' + dd;
                    }
                    if (mm < 10) {
                        mm = '0' + mm;
                    }
                    selectedDate = dd + '/' + mm + '/' + yyyy;

                    //exclude when date is out of range
                    $statsSection.each(function () {
                        var sectionDate = $(this).data('date');

                        if (process(sectionDate) < process(selectedDate)) {
                            exclude.push("[data-date='" + sectionDate + "']");
                        }
                        exclude.join(',');

                    });

                    function process(date) {
                        var parts = date.split("/");
                        return new Date(parts[2], parts[1] - 1, parts[0]);
                    }

                    filterDate = true;
                    break;
            }
            showAll = false;
        }

    });

    if (showAll) {
        $statsSection.show();
    } else {


        //HOW TO DEAL WITH THE DATES??
                if (filterDate == true) {
            alert('the following dates should be excluded from the results: ' + exclude);
        }

        //this works for the non-date selectors
        $statsSection.not($(include)).hide();
        $statsSection.filter($(include)).show();
    }
});

Ответы [ 2 ]

1 голос
/ 02 октября 2019

Итак, для элементов, не относящихся к дате, ваш метод состоит в том, чтобы вычислить селектор jquery для элементов, которые должны быть включены, а затем применить это к элементам данных.

Весьма приятный подход в том, что вы создаете несколькоФильтры jquery при создании переменной 'include'.

Сложность применения одного и того же метода для дат состоит в том, что это приводит к тесту диапазона, который трудно поместить в селектор jquery. Мое решение состоит в том, чтобы создать массив соответствующих значений даты-даты и выполнить второй фильтр на последнем шаге.

Изменения:

Шаг 1. Определите новую переменную:

var dateInclude = [];

Шаг 2. В разделе, где вы определяете, является ли дата действительной, вставьте действительные значения в массив фильтров dataInclude

//exclude when date is out of range
$statsSection.each(function () {
    var sectionDate = $(this).data('date');

    if (process(sectionDate) > process(selectedDate)) {
        dateInclude.push("[data-date='" + sectionDate + "']");
    }

});

Шаг 3: В разделе вывода мы теперь объединяемdateInclude в качестве второго фильтра. Обратите внимание, что ваши начальные фильтры работают как логическое И, но фильтры даты должны работать как логическое ИЛИ. Поэтому фильтр dateInclude применяется в операции show () в качестве второго шага.

$statsSection.hide();
include = (dateInclude.length > 0 && include === '' ? '*' : include);
dateInclude = (dateInclude.length === 0 ? ['*'] : dateInclude );
$('#info').html(include + ' :: ' + dateInclude.join());
$statsSection.filter(include).filter(dateInclude.join()).show();

Первая строка (ниже) преимущественно скрывает все div данных.

$statsSection.hide();

Следующие строки (ниже) работают с фильтрами, чтобы гарантировать, что они оба имеютстоимость. Если фильтры даты отсутствуют, мы вводим сопоставление всех и то же самое для фильтров включения для других полей выбора.

include = (dateInclude.length > 0 && include === '' ? '*' : include);
dateInclude = (dateInclude.length === 0 ? ['*'] : dateInclude );

Наконец, мы объединяем это, как показано ниже.

$statsSection.filter(include).filter(dateInclude.join()).show();

Чтобы помочь визуализировать его, я добавил некоторые выходные данные к скрипке

Например, выбор server = NicNicFunGame и date = последние шесть месяцев создает фильтры:

$statsSection.filter("[data-server='NicNicFunGame']").filter("[data-date='27/09/2019'],[data-date='03/07/2019']").show();

См. Мою рабочую скрипку наhttps://jsfiddle.net/JamesE442/qktfbp15/38/

1 голос
/ 02 октября 2019

Вы можете хранить все свои stats-section в массиве объектов и осуществлять поиск с помощью фильтра массива

var t0 = performance.now(); 
var initialized = false;
var $select = $('#stats_filter select'); 
function initialize() {
  mySelectors = [];
  $statsSection = $('.stats-section');
    console.log("First search will be costly");
    $($statsSection).each(function (i, e) {
        let temp = $(e).data();
        temp.element = $(e);
        let myDate = temp.date.split("/");
        temp.date = new Date(myDate[1] + "/" + myDate[0] + "/" + myDate[2]).getTime();//fix date format and convert to timestamp
        mySelectors.push(temp);
    });
    initialized = true;
}



$select.change(function () {
    var t0 = performance.now();
    if (!initialized)
        initialize();
    var result = mySelectors;
    $select.each(function () {
        var val = $(this).val(); //you don't need to search the selected child
        if (val !== 'all') {
            switch ($(this).prop('id')) {
                case 'select-server':
                    result = result.filter(obj => {
                        return obj.server === val;
                    });
                    break;
                case 'select-track':
                    result = result.filter(obj => {
                        return obj.track === val;
                    });
                    break;
                case 'select-car':
                    result = result.filter(obj => {
                        return obj.car === val;
                    });
                    break;
                case 'select-date':
                    var selectedDate = new Date(new Date().setDate(new Date().getDate() - val)).getTime(); // timestamp
                    result = result.filter(obj => {
                        return obj.date > selectedDate;
                    });
            }
        }

    });
    $($statsSection).hide();
    $.each(result, function (i, e) {
        $(e.element).show();
    });
    var t1 = performance.now();
    console.log("Search performance " + (t1 - t0) + " milliseconds.");
});
var t1 = performance.now();
console.log("Initialize performance " + (t1 - t0) + " milliseconds.");
.grids { clear: both;max-width: 1920px;margin: 0;}
#stats_filter_wrapper .select-wrapper { width: 25%; float:left; }
#stats_filter_wrapper .select-wrapper label { overflow: hidden; font-weight: 700; }
#stats_filter_wrapper .select-wrapper select { display: block; font-size: 16px; color: #6a6d73; line-height: 1.3; padding: 8px 25px 5px 8px; width: 100%; max-width: 100%; box-sizing: border-box; margin: 0; }
.stats-section{padding:20px 0;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="stats_filter">
    <div id="stats_filter_wrapper" class="grids">
        <div class="grid-3 select-wrapper server first">
            <label class="server">Server</label>
            <select id="select-server">
                <option value="all">All</option>
                <option value="NicNicFunGame">NicNicFunGame</option>
                <option value="GT3_races">GT3_races</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper track">
            <label class="track">Track</label>
            <select id="select-track">
                <option value="all">All</option>
                <option value="ks_brands_hatch">ks_brands_hatch</option>
                <option value="Imola">Imola</option>
                <option value="Spa">Spa</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper car">
            <label class="car">Car</label>
            <select id="select-car">
                <option value="all">All</option>
                <option value="ariel_atom_v8">ariel_atom_v8</option>
                <option value="rr_caterham_academy_620r">rr_caterham_academy_620r</option>
                <option value="ks_porsche_911_gt1">ks_porsche_911_gt1</option>
            </select>
        </div>
        <div class="grid-3 select-wrapper date">
            <label class="date">Date</label>
            <select id="select-date">
                <option value="all">All</option>
                <option value="7">Last 7 days</option>
                <option value="30">Last 30 days</option>
                <option value="182">Last 6 months</option>
                <option value="365">Last 12 months</option>
            </select>
        </div>
    </div>
</div>
<div class="stats-section" id="sectionID_1" data-server="NicNicFunGame" data-track="ks_brands_hatch" data-date="27/09/2019" data-car="ariel_atom_v8">sectionID_1</div>
<div class="stats-section" id="sectionID_2" data-server="NicNicFunGame" data-track="Imola" data-date="03/07/2019" data-car="rr_caterham_academy_620r">sectionID_2</div>
<div class="stats-section" id="sectionID_3" data-server="GT3_races" data-track="Spa" data-date="14/01/2019" data-car="ariel_atom_v8, ks_porsche_911_gt1">sectionID_3</div>
...