Изменить css класс блока и сохранить выбор в куки

Александр
Александр
1.9K
20
Александр здравствуйте! Подскажите пожалуйста и если возможно то примером, при нажатии на ссылку (Второго или третьего варианта) в данном случае речь идёт о альтернативном виде mFilter2, как можно изменить класс блока (тест) и сохранять выбор в cookies, пока не будет выбран (Первый вариант)? Блок вывода ссылок для выбора альтернативного вида в mFilter2:
[[!+my.tpls:notempty=`
<div id="mse2_tpl" class="vid" >
	<a href="#" data-tpl="0" class="[[+my.tpl0]]"> (Первый вариант)</a>
	<a href="#" data-tpl="1" class="[[+my.tpl1]]"> (Второй вариант)</a>
	<a href="#" data-tpl="2" class="[[+my.tpl2]]"> (Третий вариант)</a>
</div>
`]]
Блок (тест):
<div class="test">Тест</div>

Комментарии: 20

  1. Александр Мальцев
    Александр Мальцев
    31.10.2019, 14:00
    Привет!
    Для удобной работы на стороне клиента можно использовать библиотеку js-cookie. Как с ней работать описано здесь.
    Сохранить выбор в cookie можно осуществить так:
    <script src="js.cookie-2.2.1.min.js"></script>
    <script>
      $(document).on('click', '.vid a', function(){
        Cookies.set('vid', $(this).attr('data-tpl'));
      })
    </script>
    
    На сервере можно создать сниппет, например, getVid:
    <?php
    if($_COOKIE['vid'] == '1') {
      return 'test1';
    } else if ($_COOKIE['vid'] == '2') {
      return 'test2';
    } else {
      return 'test';
    }
    
    Далее в шаблоне:
    <div class="[[!getVid]]">Тест</div>
    
    1. Александр
      Александр
      04.11.2019, 00:33
      Александр огромное спасибо, практически то что нужно, но есть одна проблема, класс меняется после перезагрузки страницы а как в данном случае, сделать чтобы налету менялся?
    2. Александр Мальцев
      Александр Мальцев
      06.11.2019, 14:01
      Для этого нужно к элементу добавить какой-то опозновательный признак, например id:
      <div id="test" class="test">Тест</div>
      
      JS код:
      $(document).on('click', '.vid a', function () {
        var
          dataTpl = $(this).attr('data-tpl'),
          test = $('#test');
        test.removeClass();
        if (dataTpl === '1') {
          test.addClass('test1');
        } else if (dataTpl === '2') {
          test.addClass('test2');
        } else {
          test.addClass('test');
        }
        Cookies.set('vid', dataTpl);
      });
      
    3. Александр
      Александр
      08.11.2019, 15:39
      Александр здравствуйте! Спасибо, этот вариант работает как нужно, только не понятно почему при перезагрузке страницы класс сбрасывается, подскажите пожалуйста, как сделать чтобы не сбрасывался?

      И если возможно, к примеру, посетитель когда то выбрал альтернативный вид, как сделать чтобы при переходе на страницу каталога по прямой ссылке его выбор всё равно учитывался а сейчас получается так, выбираю вид он изменился, перехожу на главную, далее опять в каталог, вид становиться по умолчанию, выбор не учитывается, так как в ссылке отсутствует &tpl=2, как можно сделать, чтобы запоминался выбор на определённое время и пока посетитель сам не изменит вид?
    4. Александр Мальцев
      Александр Мальцев
      10.11.2019, 11:15
      Привет!
      Нужно указать количество дней сколько хранить куку:
      Cookies.set('vid', dataTpl, { expires: 365 });
      При загрузке страницы должно с помощью сниппета меняться.
      Если нужно через JavaScript то можно так:
      $(function(){
        var
          vid = Cookies.get('vid'),
          test = $('#test');
        if (vid !== 'undefined') {  
          test.removeClass();
          if (vid == '1') {
            test.addClass('test1');
          } else if (vid == '2') {
            test.addClass('test2');
          } else {
            test.addClass('test');
          }
        }
      });
      
    5. Александр
      Александр
      10.11.2019, 13:33
      Александр спасибо, сейчас при перезагрузке страницы всё сохраняется, но есть две проблемы, как сделать чтобы при переключении браузерных вперёд назад, тоже всё работало, сейчас получается так: выбираю вид, класс изменился как нужно, нажимаю в браузере на стрелку вернуться на предыдущую страницу, вид становиться по умолчанию всё правильно а класс остаётся не изменённым, как сделать чтобы учитывались браузерные вперёд назад?

      Так же не получается сделать чтобы учитывался выбор вида при заходе по прямой ссылке, есть ссылка на каталог, пример: сайт/каталог, перейдя по такой ссылке, вид будет по умолчанию не зависимо от того был ли он выбран или нет а как сделать чтобы учитывался выбор пользователя и в зависимости от этого добавлялось к ней (&tpl=) к примеру пару дней назад я выбрал вид на сайте, захожу сегодня на сайт на главную в меню перехожу по ссылке: сайт/каталог и попадаю в каталог с тем видом что я выбирал, то есть к ссылке добавилось сайт/каталог&tpl=2 как это сделать?
    6. Александр Мальцев
      Александр Мальцев
      14.11.2019, 14:06
      Привет! Если браузерные back и forward приводят к переходам, то ничего добавлять не нужно, код JavaScript должен выполняться и изменять класс.
      Вторую часть, если правильно понял, вам нужно выполнить средствами MODX. Создать плагин на OnHandleRequest и написать в нём код для перенаправления пользователя на нужную страницу.
    7. Александр
      Александр
      14.11.2019, 23:38
      Александр, с mfilter2 почему то, это не работает. К примеру нажимаю на альтернативный вид «Плитка» к ссылке добавляется &tpl=1 класс блока test1, далее нажимаю на вид «Список» к ссылке добавляется &tpl=2 класс блока становиться test2, теперь нажимаю на браузерную back, в ссылке изменяется на &tpl=1 а класс почему-то не меняется и остаётся test2, может это связано с тем что в mFilter2 при нажатии на браузерную back, страница не перезагружается а аяксом всё делается может поэтому класс не изменяется?
    8. Александр Мальцев
      Александр Мальцев
      15.11.2019, 12:31
      В mFilter2 для этого есть же событие mse2_load. В обработчик этого события просто добавьте нужный код:
      $(document).on('mse2_load', function(){
        ...
      });
      
    9. Александр
      Александр
      15.11.2019, 23:19
      Пробую таким образом:
      $(document).on('click', '.vid a', 'mse2_load',   function(e, data) {
       var
       dataTpl = $(this).attr('data-tpl'),
        test = $('#test');
        test.removeClass();
        if (dataTpl === '1') {
          test.addClass('test1');
        } else if (dataTpl === '2') {
          test.addClass('test2');
        } else {
          test.addClass('test');
        }
        Cookies.set('vid', dataTpl);
      
      objSSF.addSelectedFilters(ss_form_filter_css_id+" "+ss_container_filter_el,ss_container_filter_el, ss_type_filtered);
      		});
      но проблема остаётся, не правильно возможно что-то делаю?
    10. Александр Мальцев
      Александр Мальцев
      17.11.2019, 03:43
      Событие назваыется mse2_load, а не click. Поэтому нужно так:
      $(document).on('mse2_load', function(){
        var
          dataTpl = $(this).attr('data-tpl'),
          test = $('#test');
          // и т.д. код... 
      });
      
      А прописывать условия, если они нужны нужно уже в обработчике.
    11. Александр
      Александр
      18.11.2019, 02:26
      Александр спасибо за ответ я изначально так и делал но у меня не работало потом уже полез в скрипт mfilter2 и там в функции mse2_load, пытался добавить код, не совсем ясно честно говоря, сейчас в шаблоне у меня так:
      <script>
      $(document).on('mse2_load', function(){
        var
           dataTpl = $(this).attr('data-tpl'),
          test = $('#test');
        test.removeClass();
        if (dataTpl === '1') {
          test.addClass('test1');
        } else if (dataTpl === '2') {
          test.addClass('test2');
        } else {
          test.addClass('test');
        }
        Cookies.set('vid', dataTpl);
      });
      </script>
      <script>
      $(document).on('click', '.vid a', function () {
        var
          dataTpl = $(this).attr('data-tpl'),
          test = $('#test');
        test.removeClass();
        if (dataTpl === '1') {
          test.addClass('test1');
        } else if (dataTpl === '2') {
          test.addClass('test2');
        } else {
          test.addClass('test');
        }
        Cookies.set('vid', dataTpl);
      });
      </script>
      Я понимаю что делаю не правильно, но не могу допереть что и куда и по поводу обработчика, тоже не понял, подскажите пожалуйста как в данном случае правильно прописать, чтобы работали браузерные back и forward?
    12. Александр Мальцев
      Александр Мальцев
      20.11.2019, 14:21
      А что при браузерных back и forward событие mse2_load не происходит?
      Воспользуйтесь отладчиком кода в браузере или хотя бы просто добавьте в функцию вывод какого-нибудь значения в консоль.
      $(document).on('mse2_load', function(){
        console.log('mse2_load');
        ...
      });
      Если сообщение в консоли выводится, то событие значит происходит.
      А почему думаете, что делаете что-то неправильно? Если один и тот же код должен выполняться при разных событиях, то по-другому не так.
      Но такой код, конечно, нужно упростить. Для этого нужно создать функцию, а затем указать её в качестве обработчиков нужных событий.
      var myfunc = function() { ... }
      $(document).on('mse2_load', myfunc);
      $(document).on('click', '.vid a', myfunc);
      Кроме этого, возможно вам код нужно выполнять не только при наступлении этих событий, а также, например после загрузки страницы:
      $(document).ready(myfunc);
      
    13. Александр
      Александр
      20.11.2019, 17:13
      Событие mse2_load происходит, но если посмотреть в консоле, код, класс test видно мигает, но не изменяется, это если при нажатии back и forward.

      Что самое интересное при изменении вида, перестаёт правильно работать изменение класса блока, это если используешь событие mse2_load, происходит следующее, нажимаю изменить вид, класс блока test на доли секунды изменяется как и необходимо, именно на то время, пока происходит событие mse2_load и становиться по дефолту.

      Так же если посмотреть в консоле куки что-то не то твориться при нажатии на вид на доли секунды появляется нужная запись и сразу меняется на (undefined).

      Делаю так:
      <script>
      var myfunc = function() {  dataTpl = $(this).attr('data-tpl'),
          test = $('#test');
        test.removeClass();
        if (dataTpl === '1') {
          test.addClass('test1');
        } else if (dataTpl === '2') {
          test.addClass('test2');
        } else {
          test.addClass('test'); 
        }
         console.log('mse2_load');
        Cookies.set('vid', dataTpl); 
      }
      $(document).on('mse2_load', myfunc);
      $(document).on('click', '.vid a', myfunc);
      $(document).ready(myfunc);
      </script>
      <script>
      $(function(){
        var
          vid = Cookies.get('vid'),
          test = $('#test');
        if (vid !== 'undefined') {  
          test.removeClass();
          if (vid == '1') {
            test.addClass('test1');
          } else if (vid == '2') {
            test.addClass('test2');
          } else {
            test.addClass('test');
          }
        }
      });
      </script>
      Александр, да по этому я и подумал что не правильно делаю, так как размещаю один и тот же код несколько раз, спасибо сейчас более понятно по этому поводу.

      Если всё обобщить, сейчас выглядит примерно так, пока происходит событие mse2_load, всё срабатывает ненадолго, кроме back и forward так как при нажатии на них, класс test, просто мигает но не изменяется, даже на то время пока происходит событие.
    14. Александр Мальцев
      Александр Мальцев
      21.11.2019, 14:21
      Значит событие mse2_load не подходит. В этом случае нужно внести изменения в файл "\assets\components\msearch2\js\web\default.js":
      afterLoad: function () {
        $(this.options['wrapper']).removeClass( this.options['loading_class']);
        this.results.css('opacity', 1);
        this.filters.find('.' + this.options.disabled_class).prop('readonly', false).removeClass(this.options.disabled_class);
        $(document).trigger('mse2_afterload');
      },
      
      После этого изменить:
      $(document).on('mse2_afterload', myfunc)
      ;
    15. Александр
      Александр
      21.11.2019, 20:36
      Спасибо, сейчас ситуация такая, нажимая на изменить вид, всё работает как и работало с изначальным вариантом кода, класс изменяется с cookies тоже проблем нет, но back и forward по прежнему не работает, на событие тоже не реагирует с чем это может быть связано?

      Этот параметр:
      $(document).ready(myfunc);
      я убрал, так как если с ним то проблемы с куками при перезагрузки страницы.
    16. Александр Мальцев
      Александр Мальцев
      22.11.2019, 13:21
      Для работы с историей в браузере есть событие popstate. Попробуйте поработать с этим событием:
      window.addEventListener('popstate', function (e) {
      
      });
    17. Александр
      Александр
      22.11.2019, 17:57
      Сделал так, вернул в default.js всё как было, скрипт поставил тот, что изначально был и добавил второй:

      <script>
      window.addEventListener('popstate', function (e) {
        dataTpl = $(this).attr('data-tpl'),
          test = $('#test');
        test.removeClass();
        if (dataTpl === '1') {
          test.addClass('test1');
        } else if (dataTpl === '2') {
          test.addClass('test2');
        } else {
          test.addClass('test');
        }
       Cookies.set('vid', dataTpl);
      });
      </script>
      Сейчас происходит так, всё что работало так и работает но при нажатии на браузерную back, класс сбрасывается на test и в куках undefined при дальнейших нажатиях на back или forward не чего не происходит, возможно я что-то не правильно делаю?
    18. Александр
      Александр
      22.11.2019, 18:27
      Александр как я понимаю, событие сейчас срабатывает, так как класс сбросился при нажатии на back, но как правильно сделать, чтобы работало как нужно?
    19. Александр Мальцев
      Александр Мальцев
      24.11.2019, 11:37
      Не знаю, нужно разбираться из-за чего это. Какой код это выполняет, может это на клиенте, а может и на сервере…