Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Нужно передать значение переменной при нажатии button (https://javascript.ru/forum/dom-window/53900-nuzhno-peredat-znachenie-peremennojj-pri-nazhatii-button.html)

Aggao 23.02.2015 03:30

Нужно передать значение переменной при нажатии button
 
Здравствуйте. Помогите передать значение переменной "txtName" и $buttonName = true на страницу при нажатии кнопки "buttonName" без перезагрузки страницы.

if ($_POST['buttonName']) { echo $_POST['txtName']; }

}
echo '
<input id="txtId" name="txtName" type="text" value="">
<input id="buttonId" name="buttonName" type="button" onClick="" value="Добавить">';

laimas 23.02.2015 05:41

Ajax поможет, XMLHttpRequest или один из методов jQuery, если используется.

if ($_POST['buttonName']) { echo $_POST['txtName']; }

А без кнопки buttonName, что не прокатит?

if ($_POST['txtName']) { echo $_POST['txtName']; }

Aggao 23.02.2015 10:41

Это добавление товаров в корзину. Поэтому нажатие кнопки "добавить" обязательно должно быть. Я не очень владею ajax, поэтому и прошу помощи. Немного осваиваю js, но знаний не хватает на некоторые моменты связанные с отправкой переменных через формы не подгружая страницы.

Aggao 23.02.2015 10:42

Laimas, а Вы не могли бы подробнее с кодом показать как осуществить передачу переменной нажатием кнопки?

laimas 23.02.2015 16:45

Ну если корзина и добавление товара, то 'txtName', это не то что нужно, нужен идентификатор товара.

Вы используете в этом проекте jQuery или нет?

Aggao 23.02.2015 18:54

Да использую. Нужна любая реализация задуманного. Js мне хоть как-то знаком, с jquery все сложнее :)

laimas 23.02.2015 19:21

Ну на jQuery как раз сложностей нет, все намного проще. Выберите упрощенные его методы Ajax .get() или .post(), их вполне хватит. Попробуйте хотя бы по примерам что-то написать, а далее с конкретными проблемами можно и на форум.

Aggao 01.03.2015 00:46

Хотелось бы на примере увидеть. Сейчас пытаюсь изучить ajax, но не все моменты понятны. Нужен пример.

laimas 01.03.2015 02:40

Так примеры есть и по ссылке. Ну если не понятно как их задействовать конкретно к кнопке и полю ввода, то можно поступить например так - поля input, это поля вне формы, если не подразумевается добавление N-товаров с одной страницы, то есть запрос на добавление, это добавление только одного товара. Пусть все товары на странице отображаются в списке, и элемент UL имеет id "products", в нем, а не по всей странице и нужно искать кнопки инициализирующие запрос сервера:

<ul id="products">
    <li><input type="number" name="pid[100]" value="1" min="1"> <button></button></li>
    <li><input type="number" name="pid[212]" value="1" min="1"> <button></button></li>
</ul>


Поле выбора количества товара лучше сделать типа number - в Opera, Chrome, в последнем FF такое поле будет иметь кнопки. Старые браузеры будут "понимать" такое поле как text. Имя поля, это ключ содержащий идентификатор товара, в примере равен pid. На сервере идентификатор можно получить так: (int)key($_POST['pid']).

Кнопки добавления по умолчанию, это что-то кругленькое, с иконкой корзины к примеру, а по нажатию кнопке добавляется класс "send", при котором изображение кнопки изменятся на gif-анимацию, крутилку указывающую что идет обмен с сервером.

На время запроса сервера нужно блокировать запросы на добавление товара, а по окончании снимать блокировку. Это можно сделать с помощью двух методов jQuery - ajaxStart и ajaxStop, которые можно привязать к любою объекту. В итоге получится, что-то такое:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
function toBasket(o) {
    $.post('url', o.attr('name')+'='+o.val(), function(d) {
        //d содержит ответ сервера
        //удаляем анимацию у кнопки
        o.next().removeClass('send');
    })
}

$(function() {
    var add = $('#products').find('button');
    add.click(function() {
        //добавляем анимацию кнопке и передаем количество товара серверу
        toBasket($(this).addClass('send').prev())
    }).on({
        ajaxStart: function() {
            //блокируем отправку 
            add.prop('disabled', 1)
        },
        ajaxStop: function() { 
            //разрешаем отправку
            add.prop('disabled', 0) 
        }   
    });
});
</script>


PS. Подправил, совершенно из головы вылетел идентификатор товара )

Aggao 05.03.2015 00:54

Цитата:

Сообщение от laimas (Сообщение 359089)
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
function toBasket(o) {
    $.post('url', o.attr('name')+'='+o.val(), function(d) {
        //d содержит ответ сервера
        //удаляем анимацию у кнопки
        o.next().removeClass('send');
    })
}

$(function() {
    var add = $('#products').find('button');
    add.click(function() {
        //добавляем анимацию кнопке и передаем количество товара серверу
        toBasket($(this).addClass('send').prev())
    }).on({
        ajaxStart: function() {
            //блокируем отправку 
            add.prop('disabled', 1)
        },
        ajaxStop: function() { 
            //разрешаем отправку
            add.prop('disabled', 0) 
        }   
    });
});
</script>


Продублировал Ваш код на свой сервер.
1. Добавил скрипт между тегами <head> </head>
2. Кнопки вывел за форму (form) и добавил стиль к кнопкам .send, прописав его в css.

Ничего не получилось. :(
Изначально стиль прописывается у кнопки, и при нажатии тоже срабатывает. Но id товара не передается. Как было 0, так и осталось. Прописал строку «Номер: (int)key($_POST['pid'])» прямо под списком с кнопками.

Я явно что-то не учел :)

laimas 05.03.2015 06:11

<?
session_start();
//база товаров
$products = [
    23 => ['price'=>120, 'name'=>'Товар 1'], 245 => ['price'=>230, 'name'=>'Товар 2'], 39 => ['price'=>150, 'name'=>'Товар 3'], 109 => ['price'=>380, 'name'=>'Товар 4']
];

//запрос на добавление товара
if($_POST) {
    if($pid = (int)key(current($_POST)) AND $val = (int)$_POST['pid'][$pid]) { //что нам шлют?
        //sleep(1); //убрать комментарий для проверки корректности действий на клиенте под локальным сервером
        //проверяем есть ли такой товар в базе и, если требуется, то и наличе его на складе
        if(array_key_exists($pid, $products)) {
            //добавляем товар в корзину
            $_SESSION['basket'][$pid] = [$val, $products[$pid]['price'], [$products[$pid]['name']]];
            //получаем и возвращаем всего в корзине
            exit(json_encode(totalBasket()));    
        } else exit(json_encode(['msg'=>'Нет в наличии']));
    } else exit;
}

function totalBasket() {
    $cart = &$_SESSION['basket'];
    return [array_sum(array_map('current', $cart)), array_sum(array_map('array_product', $cart))];
}
?>

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style>

#short-basket {
    width: 700px;
    height: 50px;
    line-height: 50px;
    padding-left: 10px;
    background: #eee;
    margin: 0 auto;
}

#products {
    list-style: none;
    padding: 0;
    width: 700px;
    margin: 20px auto;
}

#products li {
    display: inline-block;
    width: 300px;
    vertical-align: top;
    margin: 0 30px 50px 0;
}

#products li input {
    width: 60px;
}

button {
    padding: 2px 10px 2px 20px;
    border: 0;
    border-radius: 2px;
    background: #ddd url(data:image/gif;base64,R0lGODlhCgAKAIAAAAD/AAAAACH5BAAAAAAALAAAAAAKAAoAAAIIhI+py+0PYysAOw==) no-repeat 5px 50%;
    cursor: pointer;
}

.send {
    background-image: url(data:image/gif;base64,R0lGODlhCgAKAIAAAP8AAAAAACH5BAAAAAAALAAAAAAKAAoAAAIIhI+py+0PYysAOw==);
}

</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>

var add;

function toBasket(o) {
    $.post(location, o.attr('name')+'='+o.val(), function(d) {
        if(d.msg) {
            alert(d.msg) //нет в наличии
        } else {
            //отображаем состояние корзины
            $('#short-basket').find('b')
                              .eq(0)
                              .text(d[0]) //товаров
                              .end()
                              .eq(1)
                              .text(d[1]+'.00'); //на сумму
        }
        //удаляем анимацию у кнопки
        o.next().removeClass('send');
        //снимаем блокировку
        add.prop('disabled', 0)
    }, 'json')
}
 
$(function() {
    add = $('#products').find('button');
    add.click(function() {
        //блокируем отправку
        add.prop('disabled', 1)
        toBasket($(this).addClass('send').prev())
    });
});

</script>     
</head> 

<body>
<div id="short-basket">В корзине: товаров <b>0</b>, на сумму <b>0.00</b> руб.</div>
<ul id="products">

<?
foreach($products as $k=>$v) $ul .= '<li><h4>'.$v['name'].'</h4><p>Цена: '.$v['price'].'.00 руб.</p><input type="number" name="pid['.$k.']" value="1" min="1"> <button>В корзину</button></li>';
echo $ul; 
?>

</ul>
</body> 
</html>


Кнопки вывел за форму

Нет, имеется ввиду, что форма в данном случае не нужна, используются одни элементы INPUT, главное чтобы INPUT и BUTTON были обязательно соседними элементами братьями. Если же со страницы можно добавлять в корзину сразу несколько товаров, то в этом случае удобнее было бы использовать форму, ее событие onsubmit. При этом кнопка "В корзину" будет одна, а серверу будет отправляться массив N-товаров.

Прописал строку «Номер: (int)key($_POST['pid'])»

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

Корзина на сессии, а так как время ее жизни является глобальной установкой, нельзя под каждого юзверя установить, то чтобы продлевать ее, можно периодически, например через 10 мин., опрашивать сервер асинхронным запросом без ответа. В этом случае использовать методы ajaxStart и ajaxStop нельзя, так как запросы для сессии и добавления товаров асинхронные, поэтому блокировка и снятие блокировки кнопок перенесено в инициализацию и финиш запроса добавления товаров соответственно.

Структура корзины следующая:
array(
   ID_товара => array(
      количество_товара,
      цена_товара,
      array(наименование_товара)
   )
)


В этом случае легко просчитать общее количество товаров в корзине и их общую сумму стандартными функциями РНР. Именование товара, а возможно и другие какие либо его параметры дополнительные, помещаются в корзину для того, чтобы не "дергать" постоянно базу при обращении к корзине. Все эти доп. параметры должны быть помещены в массив, иначе использовать функцию array_product() для получения произведения количества на цену будет нельзя. Заполненный же массив будет возвращать для этой функции 1, что не будет влиять на результат умножения.

Пример написан под РНР не ниже 5.4.

Aggao 05.03.2015 22:47

Вложений: 1
Цитата:

Сообщение от laimas (Сообщение 359663)
Пример написан под РНР не ниже 5.4.

Спасибо большое за полный развернутый код. Вы очень понятно и здорово все пишите. У меня правда возникла ошибка. Вставил в файл.php Ваш код. Все красиво работает, но добавляет товары в корзину по непонятному алгоритму. Если запустить страницу первый раз, то добавит нужное количество по нажатию одной из кнопок, суммируя все 4 input. Зато если повторить или задать другое число в одном из input и снова нажать button, то в корзину падает совершенно непонятное количество и сумма. Пытался как-то привести к общему знаменателю и понять в связи с чем такой подсчет, но решения не нашел. Может уделите еще немного своего драгоценного времени и поможете отладить код? Спасибо. Вам большое.

На скрине видно, что я добавил в 4 input число 10, результат корзина выдала совершенно неожиданный. :)

laimas 05.03.2015 23:05

Вы думаете это ошибка и непонятный алгоритм? :)

Нет тут ошибки и непонятно. Если к примеру добавить первого товара 2 шт., а второго 3 шт., то общее количество будет равно 5 на сумму 930. Посмотрим что у нас в массиве корзины:

<pre>
print_r($_SESSION['basket']);
</pre>

и получаем:

Код:

Array
(
    [23] => Array
        (
            [count] => 2
            [price] => 120
            [prop] => Array
                (
                    [name] => Товар 1
                )

        )

    [245] => Array
        (
            [count] => 3
            [price] => 230
            [prop] => Array
                (
                    [name] => Товар 2
                )

        )

)

Вопрос - если теперь изменить количество второго товара на 2, и вновь отправить его на севере, то какое состояние после этого будет у корзины? Ну наверное же ключ 245 корзины будет перезаписан, и общее число товаров будет равно 4, или не так? Так. А что это означает?

Измените части кода на следующие (думаю понятно будет что и где):

//запрос на добавление товара
if($_POST) {
    if($pid = (int)key(current($_POST)) AND $val = (int)$_POST['pid'][$pid]) { //что нам шлют?
        sleep(1); //убрать комментарий для проверки корректности действий на клиенте под локальным сервером
        //проверяем есть ли такой товар в базе и, если требуется, то и наличе его на складе
        if(array_key_exists($pid, $products)) {
            //добваляем товар в корзину
            $_SESSION['basket'][$pid] = ['count'=>$val, 'price'=>$products[$pid]['price'], 'prop'=>['name'=>$products[$pid]['name']]];
            //получаем и возвращаем всего в корзине
            exit(json_encode(totalBasket()));    
        } else exit(json_encode(['msg'=>'Нет в наличии']));
    } else exit;
}

function totalBasket() {
    return $_SESSION['basket'] ? [array_sum(array_map('current', $_SESSION['basket'])), array_sum(array_map('array_product', $_SESSION['basket']))] : [0, 0];
}

$tot = totalBasket();

//....

<div id="short-basket">В корзине: товаров <b><?=$tot[0]?></b>, на сумму <b><?=$tot[1]?>.00</b> руб.</div>

//........

foreach($products as $k=>$v) $ul .= '<li><h4>'.$v['name'].'</h4><p>Цена: '.$v['price'].'.00 руб.</p>'.
                                     ($_SESSION['basket'] && array_key_exists($k, $_SESSION['basket']) 
                                     ? '<p>В корзине '.$_SESSION['basket'][$k]['count'].' шт.</p>' 
                                     : '<input type="number" name="pid['.$k.']" value="1" min="1"> <button>В корзину</button></li>');


Добавьте в корзину каких либо два товара, после чего обновите странице по F5. О чем либо это говорит?

Aggao 05.03.2015 23:57

Вложений: 1
Цитата:

Сообщение от laimas (Сообщение 359801)
Вы думаете это ошибка и непонятный алгоритм? :)

Вы были правы, не совсем разобрался с корзиной. Поставил отображение array корзины и увидел, что пока сессия жива, в корзину добавлялись мною через input наименования. В результате, при новом добавлении количества, я видел непонятный результат. Я поставил у каждого товара количество 1 и все встало на свои места (на фото видно) :) Сразу появились вопросы :)

1. Для чего нужен sleep (1)?
2. Как сделать кнопку reset корзины, она там не будет лишней.
3. При обновлении страницы корзина показывает количество 0, сумма 0. Хотя в array корзины товары есть в каком-то количестве. Как это исправить? Я еще не попробовал Ваш новый код. Возможно он это и исправляет, сейчас займусь им :)

Цитата:

Сообщение от laimas (Сообщение 359801)
Вопрос - если теперь изменить количество второго товара на 2, и вновь отправить его на севере, то какое состояние после этого будет у корзины? Ну наверное же ключ 245 корзины будет перезаписан, и общее число товаров будет равно 4, или не так? Так. А что это означает?

Вот тут тоже интересный момент. При повторном добавление количества в корзину, я на php делал проверку, если такой товар не добавлен в таблицу базы от данного пользователя (который привязан к сессии по id), тогда мы создаем товар для него и ставим туда количество полученное из input, а если товар уже есть в корзине этого пользователя, тогда суммируем его.

laimas 06.03.2015 00:26

1. Для чего нужен sleep (1)?

Для того чтобы проверить работу кнопок (анимация, блокировка) на локальном сервере. Ведь на нем все будет работать влет, и глазом моргнуть не успеете. А sleep (1) это пауза в одну секунду перед выполнением скрипта, а значит и ответа сервера, чтобы удостовериться, а потом убрать это. На реальном же сервере у вас в любом случае будут задержки.

2. Как сделать кнопку reset корзины, она там не будет лишней.

Либо поместить ul (это в примере, у вас может быть и что-то иное) в форму и использовать ее стандартную кнопку reset, либо любую кнопку, и обработчик ее на jQuery, например:
<button id="reset">Сбросить</button>
//в стилях кнопок
button:not([id=reset]) { //...
//либо можно оформить под кнопку reset любой иной элемент, и не трогать стили кнопок
//код
$('#reset').click(function() {
    $('#products').find('input').val(1);  
})


При использовании формы и input type=reset, в случае, если потребуется работать с элементами input, не забывайте об этой кнопке.

3. При обновлении страницы корзина показывает количество 0, сумма 0. Хотя в array корзины товары есть в каком-то количестве. Как это исправить? Я еще не попробовал Ваш новый код. Возможно он это и исправляет, сейчас займусь им

Займитесь, именно исправления это и учитывают.

если такой товар не добавлен в таблицу базы от данного пользователя (который привязан к сессии по id), тогда мы создаем товар для него и ставим туда количество полученное из input, а если товар уже есть в корзине этого пользователя, тогда суммируем его.

Вот тут действительно интересно. Мой пример в первой его инкарнации, это не только добавление, но и редактирование корзины со страницы товаров. Я ведь не зря вопросы задавал. То есть, после того как товар добавился в корзину, можно добавить сообщение у товара "В корзине", а текст кнопки сменить с "В корзину" на "Изменить".

А в вашем случае "а если товар уже есть в корзине этого пользователя, тогда суммируем его" при каждом добавлении товара надо и сообщать, и сбрасывать значение поля ввода в единицу, иначе это будет не добавление, а бардак :)

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

Aggao 06.03.2015 10:52

Сброс ресет не работает на jquery.

Если я правильно понимаю этот код, то первая строка запускает функцию при нажатии на кнопку reset, а функция обращается к id = products, где ищет все input и устанавливает для них параметр val в 1.

$('#reset').click(function() {
$('#products').find('input').val(1);
})

Вот этот val = 1 должен сбрасывать удалять товары из корзины полностью, т.е. проставить количество всех товаров в 0. Я попробовал просто удалить сессию и все сбрасывается, но это команда php, а как без перезагрузки реализовать? :) можно конечно через форму указать тип кнопки и так чистить, у меня так и чистится на данный момент корзина, но интересует именно переделка корзины с отсутствием перезагрузки страниц. Я еще вечером попробую разобраться в вашем коде, пока не все понятно, учусь еще на ваших примерах :)

laimas 06.03.2015 11:45

Естественно, что этот код устанавливает значения по умолчанию (1) в полях ввода, а сервер не запрашивается при этом, и естественно корзина не удаляется. Это как пример реализации "очистить форму, которой нет". А добавлять запрос к серверу я не стал по двум соображениям (добавление в корзину асинхронное, это важно):

1) Представим, что я ваш покупатель, и на странице А купил три бублика, на странице Б 5 кило конфет к бубликам, на странице В пакетик чая, а потом подумал, да ну его нафик, съем и так, всухомятку. Жму на кнопку reset, предполагая, что таким образом удаляю чай из корзины. Представляете мой ужас, когда я вернувшись на страницу А, пойму что сегодня останусь голодным?

Дело хозяйское, но по моему эта кнопка для корзины, это вред. Корзина в примере, это не корзина как таковая, это ее краткое представление. Вы когда в магазине реальном покупаете что-то, ведь в уме считаете наличие суммы в кармане и хватит ли ее на покупки? Вот для этого и служит краткое представление корзины в интернет магазине.

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

2) Корзина, это всего лишь часть задачи - приобретения товара в магазине. А задача, это от выбора товара до оформления заказа. И эту задачу надо решать комплексно, так чтобы сервер и клиент не каждый сам по себе, а единое. Это идея, интерфейс обслуживающий эту идею, удобное представление данных, чтобы сценарии этого интерфейса были оптимальны. А вот взять к примеру мой пример по добавлению товара, а потом притулить к нему кнопку "Сбросить", нагрузив сервер этой задачей как отдельным запросом, так не пойдет.


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