Javascript-форум (https://javascript.ru/forum/)
-   jQuery (https://javascript.ru/forum/jquery/)
-   -   Как получить данные из БД и вывести в модальном окне (https://javascript.ru/forum/jquery/78477-kak-poluchit-dannye-iz-bd-i-vyvesti-v-modalnom-okne.html)

LingVist 19.09.2019 12:37

Как получить данные из БД и вывести в модальном окне
 
Доброго дня всем.
Пытаюсь сделать карточку быстрого просмотра товара, как сделано тут - https://likadress.ru/
Повесил событие на кнопку
$(".element-view").on("click", function(){
        let id_product = $(this).attr("id_product");

            $.ajax({
                url: laroute.route('product.show', {id_product}),
                type: 'GET',
                dataType: "json",
                data:{id:id_product},
                success: function(response){
                    console.log("OK");
                    $(".modal_details").addClass("show-modal");
                },
                error: function (response) {
                    console.log("NO")
                }
            });
    });

В консоли получаю ответ ОК.
В контроллере написал (все это дело хочу реализовать на Laravel):
public function show($id)
    {

        $product = Product::find($id);
        return response()->json($product);
    }


Вопрос - как получить переменную в модальном окне и как потом вывести данные о товаре? Может кто ткое уже делал? Поделитесь опытом.
Спасибо.

laimas 19.09.2019 13:12

Цитата:

Сообщение от LingVist
как получить переменную в модальном окне

Какую переменную? Вот это - return response()->json($product);, должно быть выводом в браузер, а данные из response получить, поместить в соответствующие элементы $(".modal_details"), который потом показать.

LingVist 19.09.2019 13:50

Может я неправильно выразился. Говоря о переменной, я и имел в виду $product.
Цитата:

Сообщение от laimas
а данные из response получить, поместить в соответствующие элементы $(".modal_details"), который потом показать.

Вот именно с этим у меня и трудности - как эти данные получить и показать? Файл достаточно большой, чтобы описывать его в скрипте

laimas 19.09.2019 14:41

Цитата:

Сообщение от LingVist
я и имел в виду $product

Никак, это переменная на сервере, а итогом обращения к методу show контроллера должен быть вывод в браузер. При этом если вывести в консоль на клиенте ответ сервера console.log(response), то это должен быть объект, если $product, это ассоциированный массив, либо массив, если если $product, это индексный массив. А далее данные этого массива нужно поместить на страницу. Например, панель "modal_details" имеет элемент с id "test", а $product содержит ключ "test", значение которого нужно поместить в этот элемент. Значит на клиенте нужно выполнить $('#test').text(response.test).

Вот так получая значения свойств объекта response (ключей $product) непосредственно или обходом в цикле и помещайте их в нужное. А что там у вас в $product/response, что из него во что помещать никто ведь не знает на форуме, поэтому конкретно никто ничего и не скажет.

LingVist 19.09.2019 15:06

Вывод console.log(response) показывает пустые скобки {}
Может я неправильно ajax-запрос написал?

laimas 19.09.2019 15:52

Ну в самом запросе нет ошибок, а верен ли путь и данные запроса, этого я не знаю. Что касается {} в консоли, то это означает, что $product, то есть то что возвращено Product::find($id), является пустым объектом, то есть на клиент будет отдан json "{}". Причину искать нужно на сервере, либо не те параметры в запросе передает клиент.

LingVist 19.09.2019 16:30

URL неправильно написал. Теперь нормально, в консоли выдает
{"id":53,"title":"\u0411\u0440\u044e\u043a\u0438 LB 52-071","alias":"bruki-LB-52-071-","meta_title":"\u0411\u0440\u044e\u043a\u0438 LB 52-071","meta_description":"","meta_keywords":"","status":"","sizes":null,"price":560,"articul":"","category_id":7,"category_alias":"womans","created_at":null,"updated_at":null}


Но когда пишу
success: function (response) {
                    $(".modal_details h1").html(response.title);
                    $('.modal_details').addClass("show-modal");
                },

Опять что-то не так?

laimas 19.09.2019 17:12

Цитата:

Сообщение от LingVist
Опять что-то не так?

А что не так, панель появляется, а заголовок пуст? Я же не знаю всю html-структуру панели modal_details, как я могу знать что не так. Вероятно, что селектор ".modal_details h1" не верный.

LingVist 20.09.2019 11:29

Все получилось, данные выводятся, спасибо Вам за помощь.
Но теперь встала другая проблема - картинки к товару хранятся в другой таблице, связанной с первой. Я получил значения и отправил из контроллера две переменные так
return response()->json([$images, $product]);

В итоге получаю массив, в консоли это выглядит так:
(2) [{…}, Array(5)]
0: {id: 53, title: "Брюки LB 52-071", alias: "bruki-LB-52-071-", meta_title: "Брюки LB 52-071", meta_description: "", …}
1: Array(5)
0: {id: 1, img: "01.jpg", product_id: 53, created_at: null, updated_at: null}
1: {id: 2, img: "02.jpg", product_id: 53, created_at: null, updated_at: null}
2: {id: 3, img: "03.jpg", product_id: 53, created_at: null, updated_at: null}
3: {id: 4, img: "04.jpg", product_id: 53, created_at: null, updated_at: null}
4: {id: 5, img: "05.jpg", product_id: 53, created_at: null, updated_at: null}


Из первого массива получаю значения в срипте таким образом:
$(".product-title h1").text(response[0].title);
...


Все получается нормально. А вот с картинками беда - их нужно выводить в цикле. В шаблоне это выглядит так

<ul class="product-preview">
                                @foreach($product->image as $item)
                                    <li class="">
                                        <img src="{{ asset('img') }}/catalog/{{ $product->category_alias }}/{{ $item->img }}" alt="">
                                    </li>
                                @endforeach
                            </ul>


Как мне все это дело правильно написать в скрипте?

Спасибо.

laimas 20.09.2019 11:38

Цитата:

Сообщение от LingVist
В шаблоне это выглядит так

Это РНР код, серверный, а это 0: {id: 1, img: "01.jpg", product_id: 53, created_at: null, updated_at: null}... JS объект. Вопрос - если шаблон уже выводит на странице изображения, то зачем получать объект с информацией о них? Или это иные изображения?

PS. Кстати, зачем у foreach "собака" (надеюсь знаете для чего она) если родитель (UL) выводится без проверки наличия изображений, а $product->image по идее либо пустой массив/объект должен быть, что не вызовет ошибки, либо null, что не мешало бы проверить до цикла?

LingVist 20.09.2019 11:50

Да, изображения будут другие, получаемые из БД, шаблон для примера

Собака - это не для проверки, это особенности ларавелевского шаблонизатора blade, она используется для отображения циклов - @for, @foreach, проверок @if b т.д.

Я так думаю, что вместо этого цикла на сервере
@foreach($product->image as $item)
    <li class="">
     <img src="{{ asset('img') }}/catalog/{{ $product->category_alias }}/{{ $item->img }}" alt="">
</li>
@endforeach

нужно сделать цикл в скрипте, а потом уже подставить в UL
Вопрос - возможно такое?

laimas 20.09.2019 12:21

Ну если шаблонизатор, тогда ...

То есть нужно точно такой же html код получить как и в шаблоне? Если да, то response.title уже не получиться, ибо response это массив, значит response[0].title. А изображения это response[1]. Обходите циклом его и создавайте элементы li c изображениями, данные для которых берите из этого массива:

$.each(response[1], function() {
    //тут элементы этого массива, например имя изображения (насчет путей к ним не известно)
    this.img
})


Как создавать и добавлять элементы в JQ думаю не надо рассказывать.

LingVist 20.09.2019 16:19

Огромное спасибо, все работает. Добавляю картинки так:
$(".product-preview").append("<li><img src='{{ asset('img') }}/catalog/"+response[0].category_alias+"/"+this.img+"'></li>");

Только небольшой косяк - после закрытия модального окна продукта, если открыть следующее окно, то старые картинки остаются, а к ним добавляются новые. Подозреваю, что дело в методе append(). Может какой другой использовать или сделать прерывание функции после открытия окна? Я пробовал добавить return false, не помогло

laimas 20.09.2019 16:49

Можно очищать перед запросом родителя - $(".product-preview").empty(), можно не .append(), а готовить html и вставлять его, старый при этом будет перезаписан. Но, если "открыть следующее окно" означает повторное открытие с теми же данными (ранее полученными), то выгоднее перед запросом проверять - если родитель $(".product-preview") пустой, то делаем запрос и заполняем его данными, и показываем, иначе только показываем.

PS. А откуда на клиенте может взяться {{ asset('img') }}? Это ведь переменная серверная, которая передается в шаблонизатор.

LingVist 20.09.2019 17:08

$(".product-preview").empty() работает прекрасно
Спасибо Вам за помощь, удачи Вам и здоровья!!

laimas 20.09.2019 17:11

А {{ asset('img') }}?

LingVist 20.09.2019 17:25

Забыл :))
Это адрес сайта и папка img. В принципе, можно было написать просто /img, но как-то привык уже

laimas 20.09.2019 17:49

Цитата:

Сообщение от LingVist
Это адрес сайта и папка img.

Ну это понятно по месту в строке src, не понятно откуда на клиенте эта переменная? В посте 9 эта переменная в коде шаблонизатора, что понятно, а в посте 13 всплывает в клиентском коде, она что передается на клиента? И как она будет подставлена?

LingVist 20.09.2019 18:39

Подставится так
$(".product-preview").append("<li><img src='{{ asset('img') }}/catalog/"+response[0].category_alias+"/"+this.img+"'></li>");

laimas 20.09.2019 18:53

И кто же это сделает?

LingVist 20.09.2019 19:11

Я в скрипте, когда буду передавать данные, полученные от контроллера, в шаблон

$(".product-preview, .stage").empty();
                        $.each(response[1], function() {
                           

                            $(".product-preview").append("<li><img src='{{ asset('img') }}/catalog/"+response[0].category_alias+"/"+this.img+"'></li>");

                            

                        });
                        $('.modal_details').addClass("show-modal");

laimas 20.09.2019 19:41

В какой шаблон? Это РНР код шаблонизатора сервера.

@foreach($product->image as $item)
<li class="">
<img src="{{ asset('img') }}/catalog/{{ $product->category_alias }}/{{ $item->img }}" alt="">
</li>
@endforeach

это {{ asset('img') }} синтаксис его, вставка переданных в него значений в html код. Такой же синтаксис использует шаблонизатор Twig. Все шаблоны выполняет РНР, который находит это и производит подстановки.

А это JS

$.each(response[1], function() {
$(".product-preview").append("<li><img src='{{ asset('img') }}/catalog/"+response[0].category_alias+"/"+this.img+"'></li>");
});

Откуда на клиенте asset('img'), что это такое, и кто на что будет делать подмену? Нет такого в JS {{}}. Здесь это будет работать +response[0].category_alias+"/"+this.img+. В современном языке добавлено еще возможностей.

LingVist 20.09.2019 20:04

В моадльном окне, которое будет открываться, есть такой код
<div class="product-image flex flex-between js-product-slider" data-start-position="0">
                            <ul class="product-preview">

                            </ul>
                            <div class="product-image-wrap">
                                <div class="product-slider slider owl-loaded owl-drag">
                                    <div class="owl-stage-outer">
                                        <div class="owl-stage stage" style="transform: translate3d(0px, 0px, 0px); transition: all 0s ease 0s; width: 1853px;">

                                         </div>
                                    </div>
                                </div>
                                <ul class="element-labels museo">
                                    <li><span class="new">Новинка</span></li>
                                </ul>
                                <a href="/#" data-pjax="0" data-controller="Fav" class="product-fav icon link-fav is-install" data-id="6291" onclick="return false;"></a>
                            </div>
                        </div>


Вот в ul с классом product-preview я буду подставлять миниатюры
$(".product-preview").append("<li><img src='{{ asset('img') }}/catalog/"+response[0].category_alias+"/"+this.img+"'></li>");


А в див с классом owl-stage большие картинки
$(".stage").append("<div class='owl'><div class='product-slide easyzoom is-ready'><a href='{{ asset('img') }}/catalog/"+response[0].category_alias+"/"+this.img+"' data-fancybox=''><img src='{{ asset('img') }}/catalog/"+response[0].category_alias+"/"+this.img+"' alt=''></a></div></div>");


{{ asset('img') }} можно и не вставлять, достаточно будет /img
Если Вас смущают скобки {{ }}, то в ajax-запросе можно так писать и url: {{ route('product.show') }} и все работает

laimas 20.09.2019 20:36

Цитата:

Сообщение от LingVist
в ajax-запросе можно так писать и url: {{ route('product.show') }} и все работает

Оно будет работать только в том случае, если весь код что вы тут показываете, включая и js, это страница обрабатываемая шаблонизатором.

LingVist 20.09.2019 21:00

Это так, если вынести скрипт в отдельный файл, такой вариант не прокатит. Но на этот случай есть хороший пакет - https://github.com/aaronlord/laroute

laimas 20.09.2019 21:31

Цитата:

Сообщение от LingVist
Это так, если вынести скрипт в отдельный файл, такой вариант не прокатит.

Так надо было бы сразу и сказать, а то представленный сначала ajax запрос никаким боком к шаблону отношения не имеет и все далее я то представлял в контексте этого запроса, поэтому и задал вопрос как такое может быть.

LingVist 22.09.2019 11:39

laimas, в общем, так как я хотел сделать, не получилось. Может подскажете, как правильно сделать Быстрый просмотр как на этом сайте - https://likadress.ru/
Я посмотрел в исходном коже страницы, там файл модального окна пустой, данные грузятся в него после нажатия на кнопку Быстрый просмотр. Я так думаю, что после нажатия кнопки контроллер получает ID товара, выводит данные и отправляет в шаблон. Если это так, то как это реализовать?
Или может есть какие-то другие варианты?
Спасибо

laimas 22.09.2019 13:37

Быстрый просмотр чего, то что показывается при наведении на изображение товара? Если да, то это уже есть на странице и показывается при этом событии, никаких асинхронных запросов не делается. Тут ведь нет никакого окна модального, это обычная панель. Ну а способов только 2: первый, это выводить сразу на страницу затем показывая/скрывая, либо выводятся сразу данные, которые затем используются при показе, второй, это запрашивают на сервере и выводят при наведении.

LingVist 22.09.2019 14:07

Да, я имел в виду быстрый просмотр товара.

Если использовать первый способ, то придется для каждого товара выводить сразу подробные данные, я правильно понял? Но если это так, то слишком много придется грузить.

А как сделать вторым способом?

Я пытался сделать так - сделал модальное окно, в котором шаблон карточки товара. Остается только подставить идентификатор нужного товара и все будет работать. Идентификатор я получил ajax-запросом, но вот как его передать в шаблон, не могу сообразить.

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

В общем, четыре дня уже маюсь, никак не соображу

laimas 22.09.2019 14:23

Не обязательно все сразу грузить, можно подгрузить после загрузки страницы.

А вторым способом так и делается - загружается/отображается по запросу. Нет ведь никакого окна, это панель, в которую что-то вставить проще паренной репы. Тут только два момента могут быть: 1) панель уже есть на странице, ответ запроса помещают в нее и показывают, 2) создается панель, в нее помещают ответ, показывают и удаляют после события. При этом запросы либо кешируют, либо панель не удаляют, а создают новые с запросами только для тех, у которых их нет.

laimas 22.09.2019 14:44

Кстати, сервер то отвечает чистыми данными и это не такой и большой объем будет, тем более если только нужное, а не все скопом. А их то можно поместить в data атрибуты, по которым потом строить/заполнять панель, без запросов сервера.

LingVist 22.09.2019 14:53

Да, панель уже есть на странице, вот ее код
<div class="modal" id="fast-view">
    
<div class="modal-main modal-view">
    <div class="modal-view-navigation flex flex-between">
        <a data-pjax="0" href="/#" class="button button-prev js-fast-view" onclick="return false;">
            <span class="icon mr-10">&#xf10b;</span>
            Предыдущий товар
        </a>
        <a data-pjax="0" href="/#" class="button button-next js-fast-view" onclick="return false;">
            Следующий товар товар
            <span class="icon ml-10">&#xf109;</span>
        </a>
    </div>
    <div class="modal-wrap">
        <span class="modal-close js-close icon">&#xf116;</span>
        <div id="fast-view-container">Загружаем...</div>
    </div>
    <a data-pjax="0" href="/#" class="button button-full">Перейти к полной карточке товара</a>
</div>
</div>

По клику на кнопке ей добавляется класс show-modal и подгружаются данные. Вот Вы говорите в нее что-то вставить, проще пареной репы. Но это что-то нужно как-то получить? Как получать? Тем же контроллером, что показывает подробную информацию о товаре? Но он передает полученную информацию в шаблон. В шаблоне она выводится в блоке с идентификатором details_container. Я так думаю, что его-то и нужно как-то вставлять в панель этот блок

<div id="fast-view-container">Загружаем...</div>

?

laimas 22.09.2019 15:25

Отвяжите вообще данные, которые нужно потом показать на странице, от шаблонизатора. Получить эти данные при запросе страницы и поместить их в атрибуты не будет проблемой? К примеру, пусть карточки товаров содержаться в неком слое. Если наведение мыши повешено на него, то добавляем ему атрибут data-prop, в который помещаем данные о товаре (и так для всех товаров). Данные не просто json, но еще пропущенные через htmlspecialchars. Допустим, для примера эта массив:

Array
(
    [id] => 12
    [base] => /path/
    [ims] => Array
        (
            [0] => Array
                (
                    [name] => img1.jpg
                    [title] => text
                )
            [1] => Array
                (
                    [name] => img2.jpg
                    [title] => text
                )
            [2] => Array
                (
                    [name] => img3.jpg
                    [title] => text
                )
        )
)


Здесь все что требуется для вывода, например base, это путь к файлам изображений, и все прочее, и только необходимое. Вывод на страницу, это:

<div data-prop="{{prop}}">....</div>


где prop, это массив/объект переданный в шаблон как htmlspecialchars(json_encode($data), ENT_QUOTES). При наведении мыши из атрибута получается объект как:

var obj = $(this).data('prop'); //или у найденного родителя если обработчик не у родителя


И коли панель уже на странице, то размещаем эти данные в панели или строим по ним html код, который размещаем в панели. Остается показать панель, для чего используем ее метод. Например, если это Bootstrap, то способов показа ее много.

Это выгоднее чем терзать сервер, да и ответ не обязательно мгновенный. А объем данных не такой и большой будет.

LingVist 22.09.2019 15:35

Спасибо за помощь, буду пытаться. Ну а если не получится, то тогда тупо приделаю к каждому товару модалку и все.
Успехов Вам.


Часовой пояс GMT +3, время: 19:05.