Сохранение значений

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

unknownby писал(а):
2020.01.09, 09:52
yiiliveext писал(а):
2020.01.09, 09:42
Все не надо было, только функционал перезагрузки ajax-ом.
Сделаю потом снова рендер файла, а JS будет в основном представлении.
Не надо делать весь js в основном представлении.
Разрабатывайте с той точки зрения, чтобы фильтры и смену представления можно было вынести в отдельные независимые виджеты.
Виджет при этот сам по себе не занимается перезагрузкой контента страницы. Он только меняет состояние и уведомляет основную страницу о необходимости перезагрузки, это можно сделать либо через вызов функции основной страницы, либо через событие. В простейшем случае состояние можно хранить в виде глобальной переменной-объекта, которая потом в основном представлении будет собираться и отправляться в виде data в ajax-запросе.
Примерно так.

В представлении фильтра

Код: Выделить всё

$js = "
    var checkboxes = [];
    $('input[type=checkbox]').on('click', function(){
        var selection = $(this).val();
        var id = $(this)[0].id;
        var check = $(this)[0].checked;
        var value = id.split('-');
        var data;
        if(check){
            checkboxes.push(selection + '-' + value[2]);
        } else {
            checkboxes.splice(checkboxes.indexOf(selection + '-' + value[2]), 1);
        }
        pageState['checkboxes'] = '".$searchModelName."[options]=' + checkboxes;
        reloadContent();
    });";
В представлении смены представления

Код: Выделить всё

$js .= "
    $('.item-view-select > span').on('click', function(){
        pageState['itemView'] = 'itemViews=' + $(this).data('view_name');
        reloadContent();
    });
";
В основном представлении.

Код: Выделить всё

$js="
var pageState = {};
function reloadContent() {
    var data = '';
    $.each(pageState, function(key, value) {
        data += '&' + value; 
    });
    $.ajax({
            type: 'POST',
            url: '".$model->productscategory_url."',
            data: data.substr(1),
            success: function(result){
                $('#lestview-products').html(result);
            },
        });
}";
Последний раз редактировалось yiiliveext 2020.01.09, 11:57, всего редактировалось 1 раз.

unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.09, 10:57
Не надо делать весь js в основном представлении.
Разрабатывайте с той точки зрения, чтобы фильтры и смену представления можно было вынести в отдельные независимые виджеты.
Виджет при этот сам по себе не занимается перезагрузкой контента страницы. Он только меняет состояние и уведомляет основную страницу о необходимости перезагрузки, это можно сделать либо через вызов функции основной страницы, либо через событие. В простейшем случае состояние можно хранить в виде глобальной переменной-объекта, которая потом в основном представлении будет собираться и отправляться в виде data в ajax-запросе.
Фильтры будут в отдельном представлении, а смена представлений маленький блок и по сути можно не выделять в независимый виджет, но если напихать в него еще функционал, тогда да. Выделю лучше сразу в отдельное представление, с залогом на будущую доработку, мб и напихаю еще полезностей разных в него.
Собирание в одну переменную и вызов функции, которая будет в основном представлении, то что доктор прописал :)
Буду реализовывать вечером, благодарю ;)

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

unknownby писал(а):
2020.01.09, 11:20
а смена представлений маленький блок и по сути можно не выделять в независимый виджет, но если напихать в него еще функционал, тогда да. Выделю лучше сразу в отдельное представление, с залогом на будущую доработку, мб и напихаю еще полезностей разных в него.
Обычно туда еще входит сортировка. Иногда селект с деревом категорий для быстрого перехода.
Получается такой себе PageListToolbar виджет.

unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.09, 12:56
Обычно туда еще входит сортировка. Иногда селект с деревом категорий для быстрого перехода.
Получается такой себе PageListToolbar виджет.
Поработал с бесконечной подгрузкой товаров через ajax.
Тут InfiniteScrollPager мое представление с ListView.
Есть проблемы о которых ранее вы говорили, о POST и GET. Сама подгрузка товаров в InfiniteScrollPager осуществляется ajax-ом через GET запрос. Придется видимо переделывать, чтобы при фильтрации передавались параметры GET-ом и прописывались в URL страницы. Или может есть какие-нибудь идеи по тому, чтобы работало всё вместе? Чтобы работала подгрузка ajax-ом через GET (InfiniteScrollPager) при этом работала фильтрация при помощи POST, может сохранять в сессию значения и потом выводить сессию в dataProvider?
Взяв за пример эту реализацию
В контроллере есть isAjax и можно вставить костыль, но не правильная разработка таким образом :D

Код: Выделить всё

if(\Yii::$app->request->isAjax && (!\Yii::$app->request->getQueryParam('per-page') || !\Yii::$app->request->getQueryParam('page'))){
С костылем все равно нужна будет реализация другая.

Т.е. сделать так, чтобы InfiniteScrollPager в контроллере проходил условие, где добавляются значения в сессию, а просто дальше шел по контроллеру и выводил данные которые нужны вместе с данными по фильтрам

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

unknownby писал(а):
2020.01.11, 18:50
yiiliveext писал(а):
2020.01.09, 12:56
Обычно туда еще входит сортировка. Иногда селект с деревом категорий для быстрого перехода.
Получается такой себе PageListToolbar виджет.
Придется видимо переделывать, чтобы при фильтрации передавались параметры GET-ом и прописывались в URL страницы.
Именно так и надо.
Представьте ситуацию, пользователь зашел в категорию в которой десяток-другой фильтров и потратил минут десять на фильтрацию, а потом добавил товар в корзину и перешел в нее. Потом передумал и нажал в браузере кнопку "Назад". Что он получит в вашем случае, когда вы передаете POST-ом? Правильно, хреном по всей морде. И в итоге плюнет и уйдет. А вот с GET-ом такой фигни не будет, так же как и при перезагрузке страницы с выставленными фильтрами, плюс на фильтры есть ссылка. Или вы никогда не сталкивались с необходимостью скинуть ссылку на отфильтрованный набор товаров?

Если вы все реализовали из того, что я раньше писал, то там совсем немного переделать, буквально несколько строчек добавить/поменять.

unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.11, 23:18
Если вы все реализовали из того, что я раньше писал, то там совсем немного переделать, буквально несколько строчек добавить/поменять.
Всё, кроме контроллера реализовал. :)

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

unknownby писал(а):
2020.01.12, 03:09
Всё, кроме контроллера реализовал. :)
При передаче GET-ом контроллер становится совсем крохотных размеров.
Да и на фронте код можно сократить. Например, заменить вызов многострочного метода ajax() на однострочный load().
А добавится только pushState() и обработчик события popstate.

unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.12, 12:20
unknownby писал(а):
2020.01.12, 03:09
Всё, кроме контроллера реализовал. :)
При передаче GET-ом контроллер становится совсем крохотных размеров.
Да и на фронте код можно сократить. Например, заменить вызов многострочного метода ajax() на однострочный load().
А добавится только pushState() и обработчик события popstate.
Я погугли, почитал, посмотрел разные примеры.
С этим точно нужна помощь. Я в этом тёмный лес. :D


unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.12, 17:21
https://astrio.ru/blog/History-API/
Вот что наваял, но есть минимальные трудности с подгрузкой данных при помощи InfiniteScrollPager
Сохраняются состояния, выбираются товары по фильтрам, но при сработке бесконечной загрузке, в GET передается не полностью вся строка с моими данными, а добавляется номер страницы и количество товаров, которое я указал в search-е

Код: Выделить всё

?page=2&per-page=8
Контроллер

Код: Выделить всё

public function actionProducts($url)
    {
        $model = $this->findModelCategory($url);
        $searchModel = new ProductsSearch;
        $settings = Settings::findOne(Settings::SETTING_DEFAULT);
        $session = Yii::$app->session;
        $pageState = $session->has('pageState') ? $session->get('pageState') : ['itemViews' => '_product_item'];

        if(\Yii::$app->request->isAjax){
            $pageState = array_merge($pageState, \Yii::$app->getRequest()->get());
            $session->set('pageState', $pageState);
            $dataProvider = $searchModel->search($pageState, $model->productscategory_id);
        }

        $dataProvider = $searchModel->search(\Yii::$app->getRequest()->get(), $model->productscategory_id);

        return $this->render('products', [
            'model' => $model,
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
            'settings' => $settings,
            'itemView' => $pageState['itemViews'],
	]);
    }
В представлении поменял

Код: Выделить всё

$js = "
    var pageState = {};
    var listview = $('#listview-products');
    function reloadContent() {
        var data = '';
        $.each(pageState, function(key, value) {
            data += '&' + value; 
        });
        var state = data.substr(1);
        window.history.pushState(state, '".$model->productscategory_name."', '?' + state);
        loadPage('?' + state);
    }

    function loadPage(url){
        listview.load(url + ' #listview-products > *');
    }

    window.onpopstate = function(event) {
        var State = window.history.state;
        loadPage('?' + State);
    };
";
Куда двигаться? :)

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

Для начала исправить скрипт на фронте, он не совсем корректно работает.

unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.14, 10:23
Для начала исправить скрипт на фронте, он не совсем корректно работает.
Почему не корректно?

При нажатии на чекбоксы или вид представления он передает в pushState (состояние/title/дополнение к моему урлу)
В state хранится, например, ProductsSearch[options]=1-1,2-1 или со сменой представления ProductsSearch[options]=1-1,2-1&itemViews=_product_item и присоединяю к URL при помощи "?"
loadPage - загрузка страницы по новому URL
При каждом нажатии срабатывает reloadContent, сохраняется состояние и дальше загружается страница. :)

Код: Выделить всё

function reloadContent() {
        var data = '';
        $.each(pageState, function(key, value) {
            data += '&' + value; 
        });
        var state = data.substr(1);
        window.history.pushState(state, '".$model->productscategory_name."', '?' + state);
        loadPage('?' + state);
    }
Функция загрузки по урлу

Код: Выделить всё

function loadPage(url){
        listview.load(url + ' #listview-products > *');
    }
Загрузка страниц при переходе назад/вперед в браузере, если человек будет возвращаться ранее выбранным выборкам.

Код: Выделить всё

window.onpopstate = function(event) {
        var State = window.history.state;
        loadPage('?' + State);
    };
Можно конечно переделать загрузку по урлу таким образом, если в этом вопрос :D

Код: Выделить всё

function loadPage(url){
        listview.load('?' + url + ' #listview-products > *');
    }
И вызов тогда загрузки сведется к такому виду

Код: Выделить всё

loadPage(state)

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

unknownby писал(а):
2020.01.14, 11:21
yiiliveext писал(а):
2020.01.14, 10:23
Для начала исправить скрипт на фронте, он не совсем корректно работает.
Почему не корректно?
Ссылка должна быть от корня, а не только квери.
/category?filters=1-2,3-5&view=product-list а не ?filters=1-2,3-5$view=product-list

unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.14, 11:27
Ссылка должна быть от корня, а не только квери.
/category?filters=1-2,3-5&view=product-list а не ?filters=1-2,3-5$view=product-list
Так если оно так работает, зачем передавать от корня?
От корня будет /products/kategoria-11?filters=1-2,3-5&view=product-list
Будет название action и наименование url , дальше фильтры

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

И контроллер тоже неправильный. У вас dataProvider всегда перезаписывается.

unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.14, 12:10
И контроллер тоже неправильный. У вас dataProvider всегда перезаписывается.
Вот с ним знаю, что проблемы :D
Но пока не понял где и что дописать.

Тут начальная загрузка страницы

Код: Выделить всё

	$model = $this->findModelCategory($url);
        $searchModel = new ProductsSearch;
        $settings = Settings::findOne(Settings::SETTING_DEFAULT);
        $session = Yii::$app->session;
        $pageState = $session->has('pageState') ? $session->get('pageState') : ['itemViews' => '_product_item'];
        
        //убран ajax
        
        $dataProvider = $searchModel->search(\Yii::$app->getRequest()->get(), $model->productscategory_id);

        return $this->render('products', [
            'model' => $model,
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
            'settings' => $settings,
            'itemView' => $pageState['itemViews'],
	]);
А когда сработал ajax, то сделать merge, переопределить сессию с новыми данными и в search помещаем pageState.

Код: Выделить всё

	if(\Yii::$app->request->isAjax){
            $pageState = array_merge($pageState, \Yii::$app->getRequest()->get());
            $session->set('pageState', $pageState);
            $dataProvider = $searchModel->search($pageState, $model->productscategory_id);
        }
Вопрос вот в чем.
Когда работает InfiniteScrollPager он не объединяет свои значения с теми, что были указаны в сессии. Он дописывает к URL ?page=2&per-page=4
Передает при этом Query String Parameters page: 2 per-page: 4
Как сделать, чтоб объединил мои параметры из get() которые отправляются как данные с формы Form Data с параметрами, которые приходят из Query String Parameters
Думал о merge с getQueryParams(), что-то такого. Но по сути оба URL формата GET и должны были объединяться в любом случае :)

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

Если переделаете ссылки от корня, как я вам рекомендовал, то будет так

Код: Выделить всё

function loadPage(url) {
        listview.load(url + ' #listview-products > *', function() {
           try {
               $('ul.pagination > li.next a:first').attr('href', url + '&' + $('ul.pagination > li.next a:first').attr('href').split('?').pop());
           } catch (e) {}
        });
}
или так

Код: Выделить всё

function loadPage(url) {
        listview.load(url + ' #listview-products > *', function() {
           var next = $('ul.pagination > li.next a:first');
           if (next) {
               next.attr('href', url + '&' + next.attr('href').split('?').pop());
           }
        });
}
В котроллере не надо мержить весь GET и сохранять в состояние.
Последний раз редактировалось yiiliveext 2020.01.14, 13:36, всего редактировалось 5 раз.

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

Код: Выделить всё

$model = $this->findModelCategory($url);
        $searchModel = new ProductsSearch;
        $settings = Settings::findOne(Settings::SETTING_DEFAULT);
        $session = Yii::$app->session;
        if (\Yii::$app->getRequest()->get('itemViews')) {
            $itemViews = \Yii::$app->getRequest()->get('itemViews');
            $session->set('itemViews', $itemViews);
        } else {
            $itemViews = $session->has('itemViews') ? $session->get('itemViews') : '_product_item';
        }
        $dataProvider = $searchModel->search(\Yii::$app->getRequest()->get(), $model->productscategory_id);

        return $this->render('products', [
            'model' => $model,
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
            'settings' => $settings,
            'itemView' => $itemViews,
	]);

unknownby
Сообщения: 382
Зарегистрирован: 2019.11.05, 16:34
Контактная информация:

Re: Сохранение значений

Сообщение unknownby »

yiiliveext писал(а):
2020.01.14, 13:18
Если переделаете ссылки от корня, как я вам рекомендовал, то будет так

Код: Выделить всё

function loadPage(url) {
        listview.load(url + ' #listview-products > *', function() {
           try {
               $('ul.pagination > li.next a:first').attr('href', url + '&' + $('ul.pagination > li.next a:first').attr('href').split('?').pop());
           } catch (e) {}
        });
}
или так

Код: Выделить всё

function loadPage(url) {
        listview.load(url + ' #listview-products > *', function() {
           var next = $('ul.pagination > li.next a:first');
           if (next) {
               next.attr('href', url + '&' + next.attr('href').split('?').pop());
           }
        });
}
В котроллере не надо мержить весь GET и сохранять в состояние.
Если так сделать, подойдет для функции?
Не могу проверить, только вечером :D
В pushState первую переменную передавать целый url или всё же оставить state? Там же состояние страницы

Код: Выделить всё

	var state = data.substr(1);
	var url = '/products/'".$model->productscategory_url."'?' + state;
        window.history.pushState(state, '".$model->productscategory_name."', url);
        loadPage(url);
А контроллер всё уменьшается и уменьшается :)
Я бы эту конструкцию

Код: Выделить всё

	if (\Yii::$app->getRequest()->get('itemViews')) {
            $itemViews = \Yii::$app->getRequest()->get('itemViews');
            $session->set('itemViews', $itemViews);
        } else {
            $itemViews = $session->has('itemViews') ? $session->get('itemViews') : '_product_item';
        }
Сделал бы так

Код: Выделить всё

	$itemViews = $session->has('itemViews') ? $session->get('itemViews') : '_product_item';
	if (\Yii::$app->getRequest()->get('itemViews')) {
            $itemViews = \Yii::$app->getRequest()->get('itemViews');
            $session->set('itemViews', $itemViews);
        } 
$itemViews всё равно перезапишется, если был get('itemViews')

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Сохранение значений

Сообщение yiiliveext »

unknownby писал(а):
2020.01.14, 13:56
Если так сделать, подойдет для функции?
Что значит подойдет? Infinit-scroll по умолчанию работает со ссылкой $('ul.pagination > li.next a:first').attr('href'), берет ее загружает по ней данные ajax-ом, фильтрует по элементу с itemsCssClass и добавляет в элемент с itemsCssClass вашей страницы, обновляете ссылку next из полученных данных. Только скорее всего страницу всегда вторую надо ставить после загрузки фильтров, надо подумать и немного подправить эту функцию.
В pushState первую переменную передавать целый url или всё же оставить state? Там же состояние страницы
Целый
Я бы эту конструкцию
Сделал бы так
$itemViews всё равно перезапишется, если был get('itemViews')
Можно и так, но всегда будет запрос к сессиям, даже если он не нужен.
А сессии могут находиться в бд или редисе на отдельном сервере.
Если лишний запрос по сети вас устраивает, то можно и так.
Последний раз редактировалось yiiliveext 2020.01.14, 17:24, всего редактировалось 1 раз.

Ответить