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

Александр здравствуйте! Подскажите пожалуйста и если возможно то примером, при нажатии на ссылку (Второго или третьего варианта) в данном случае речь идёт о альтернативном виде 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

Александр Мальцев
Александр Мальцев
Привет!
Для удобной работы на стороне клиента можно использовать библиотеку 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>
Александр
Александр
Александр огромное спасибо, практически то что нужно, но есть одна проблема, класс меняется после перезагрузки страницы а как в данном случае, сделать чтобы налету менялся?
Александр Мальцев
Александр Мальцев
Для этого нужно к элементу добавить какой-то опозновательный признак, например 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);
});
Александр
Александр
Александр здравствуйте! Спасибо, этот вариант работает как нужно, только не понятно почему при перезагрузке страницы класс сбрасывается, подскажите пожалуйста, как сделать чтобы не сбрасывался?

И если возможно, к примеру, посетитель когда то выбрал альтернативный вид, как сделать чтобы при переходе на страницу каталога по прямой ссылке его выбор всё равно учитывался а сейчас получается так, выбираю вид он изменился, перехожу на главную, далее опять в каталог, вид становиться по умолчанию, выбор не учитывается, так как в ссылке отсутствует &tpl=2, как можно сделать, чтобы запоминался выбор на определённое время и пока посетитель сам не изменит вид?
Александр Мальцев
Александр Мальцев
Привет!
Нужно указать количество дней сколько хранить куку:
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');
    }
  }
});
Александр
Александр
Александр спасибо, сейчас при перезагрузке страницы всё сохраняется, но есть две проблемы, как сделать чтобы при переключении браузерных вперёд назад, тоже всё работало, сейчас получается так: выбираю вид, класс изменился как нужно, нажимаю в браузере на стрелку вернуться на предыдущую страницу, вид становиться по умолчанию всё правильно а класс остаётся не изменённым, как сделать чтобы учитывались браузерные вперёд назад?

Так же не получается сделать чтобы учитывался выбор вида при заходе по прямой ссылке, есть ссылка на каталог, пример: сайт/каталог, перейдя по такой ссылке, вид будет по умолчанию не зависимо от того был ли он выбран или нет а как сделать чтобы учитывался выбор пользователя и в зависимости от этого добавлялось к ней (&tpl=) к примеру пару дней назад я выбрал вид на сайте, захожу сегодня на сайт на главную в меню перехожу по ссылке: сайт/каталог и попадаю в каталог с тем видом что я выбирал, то есть к ссылке добавилось сайт/каталог&tpl=2 как это сделать?
Александр Мальцев
Александр Мальцев
Привет! Если браузерные back и forward приводят к переходам, то ничего добавлять не нужно, код JavaScript должен выполняться и изменять класс.
Вторую часть, если правильно понял, вам нужно выполнить средствами MODX. Создать плагин на OnHandleRequest и написать в нём код для перенаправления пользователя на нужную страницу.
Александр
Александр
Александр, с mfilter2 почему то, это не работает. К примеру нажимаю на альтернативный вид «Плитка» к ссылке добавляется &tpl=1 класс блока test1, далее нажимаю на вид «Список» к ссылке добавляется &tpl=2 класс блока становиться test2, теперь нажимаю на браузерную back, в ссылке изменяется на &tpl=1 а класс почему-то не меняется и остаётся test2, может это связано с тем что в mFilter2 при нажатии на браузерную back, страница не перезагружается а аяксом всё делается может поэтому класс не изменяется?
Александр Мальцев
Александр Мальцев
В mFilter2 для этого есть же событие mse2_load. В обработчик этого события просто добавьте нужный код:
$(document).on('mse2_load', function(){
  ...
});
Александр
Александр
Пробую таким образом:
$(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);
		});
но проблема остаётся, не правильно возможно что-то делаю?
Александр Мальцев
Александр Мальцев
Событие назваыется mse2_load, а не click. Поэтому нужно так:
$(document).on('mse2_load', function(){
  var
    dataTpl = $(this).attr('data-tpl'),
    test = $('#test');
    // и т.д. код... 
});
А прописывать условия, если они нужны нужно уже в обработчике.
Александр
Александр
Александр спасибо за ответ я изначально так и делал но у меня не работало потом уже полез в скрипт 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?
Александр Мальцев
Александр Мальцев
А что при браузерных 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);
Александр
Александр
Событие 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, просто мигает но не изменяется, даже на то время пока происходит событие.
Александр Мальцев
Александр Мальцев
Значит событие 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)
;
Александр
Александр
Спасибо, сейчас ситуация такая, нажимая на изменить вид, всё работает как и работало с изначальным вариантом кода, класс изменяется с cookies тоже проблем нет, но back и forward по прежнему не работает, на событие тоже не реагирует с чем это может быть связано?

Этот параметр:
$(document).ready(myfunc);
я убрал, так как если с ним то проблемы с куками при перезагрузки страницы.
Александр Мальцев
Александр Мальцев
Для работы с историей в браузере есть событие popstate. Попробуйте поработать с этим событием:
window.addEventListener('popstate', function (e) {

});
Александр
Александр
Сделал так, вернул в 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 не чего не происходит, возможно я что-то не правильно делаю?
Александр
Александр
Александр как я понимаю, событие сейчас срабатывает, так как класс сбросился при нажатии на back, но как правильно сделать, чтобы работало как нужно?
Александр Мальцев
Александр Мальцев
Не знаю, нужно разбираться из-за чего это. Какой код это выполняет, может это на клиенте, а может и на сервере…