Javascript-форум (https://javascript.ru/forum/)
-   Элементы интерфейса (https://javascript.ru/forum/dom-window/)
-   -   Работа с раскрывающимся списком (https://javascript.ru/forum/dom-window/69262-rabota-s-raskryvayushhimsya-spiskom.html)

laimas 21.06.2017 03:40

j0hnik, не порите хрени, ID = идентификатор, еще не означает, что нужно именно по нему обращаться к объекту. В данном случае ID, это зло.

Цитата:

Сообщение от ФедорН
Правильно ли я понимаю, что я document.querySelector("#id") должен заменить на что-то вроде width=document.querySelector("#form" input[name=width[]]) ?

Нет. document.querySelector(selector) вернет первый из набора. Если он один на странице, то все Ок, но если их много, то достучаться до остальных этим методом не получится. И к тому же селектор в данном случае, это строка, которая у вас с ошибкой прописана. Селектор "#form input[name=width[]]" не найдет требуемого, будет получена ошибка о некорректном селекторе, так как квадратные скобки в именах, а также точку необходимо экранировать - "#form input[name=width\\[\\]]" или "#my\\.iden" в случае идентификатора.

Но даже используя корректные селекторы и document.querySelectorAll() все равно не получится, так как элементы добавляются динамически, ранее объявленные обработчики их не затронут. Нужно делегировать обработку родителю form.

$('#form').on('change input', 'select, input', function() {
     this.value //здесь, это значение источника, а
     this //сам источник, который нужно исключить из набора остальных получаемых элементов
     var elm = $(this).closest('.roword').find('select, input').not(this) //набор остальных
})


Можно в набор включить сразу и output, перемножая значения среза элементов 0, -1 и this, помещая результат в последний в наборе (то есть output).

Кроме события change родителю делегируется обработка и события input, так как в поле ввода можно изменять значение не только стрелками, но и непосредственно вводом значения.

Ранее показанный код добавления нужно исправить, забыто об output, кроме того, по уму, поля ввода должны иметь значение по умолчанию 40 (в атрибутах min="40" max="200 и 300").

$('button').click(function() {
        $('div.roword').first()
                       .clone()
                       .appendTo($('#form'))
                       .find('select, output').val('')
                       .end()
                       .find('input')
                       .val(40)
    });


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

ФедорН 28.06.2017 13:33

laimas, спасибо Вам огромное за помощь и развернутые ответы.

По обстоятельствам только вчера добрался, внес правки, но... вообще теперь все не работает :) пытаюсь разбираться с jQuery теперь

Правильно ли я понимаю, что
window.addEventListener

это теперь
$('#form').on

дополнительно оборачивать в
$(function() {
не требуется?

laimas 28.06.2017 13:48

Цитата:

Сообщение от ФедорН
Правильно ли я понимаю, что
window.addEventListener
это теперь
$('#form').on

Нет. $('#form').on, это установка обработчика события в jQuery, и установить его можно только тогда, когда готова DOM, то есть после загрузки документа. Только по наступлению этого события, что и описывается обработчиком события $(function() ... в jQuery, будут доступны объекты документа и можно установить обработчики для них. То есть обязательно

(function() {
    $('#form').on(event, function() {
         //....
    }); 
})


window.addEventListener установка события в JS, которой и оперирует JQuey (это фреймворк написанный на JS).

Цитата:

Сообщение от ФедорН
вообще теперь все не работает

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

ФедорН 28.06.2017 20:48

Понял :)

laimas 28.06.2017 23:00

Цитата:

Сообщение от ФедорН
Добавил функцию для учета атрибутов инпутов min и max, в jsfiddle она отлично работает, а у меня в php -нет

Что именно на РНР не работает, значения min и max? Ну они и не передаются на сервер.

Что касается сервера, то я могу еще раз повторить - с точки зрения веб приложения, рассчитать на клиенте и результаты расчета отдать серверу, серверу принять и поверить, это профанация.

Грамотно, это так:

1) Опции списка color в значениях должны содержать не величины, которые для расчета, а идентификаторы этих величин.

2) Значения min и мах для полей типа number должен задавать север.

На основании 1 и 2 следует, что параметры всех величин сервер знает, а значит получая идентификатор списка он может проверить истинность выбранного. Выбранные величины ширины/высоты на корректность сервер может проверить, зная величины min и мах.

Вы так не поступаете, что там у вас за проблемы не знаю. Но если вы доверяете все клиенту, то и <output></output> не годится, так как его значение на сервер не передается, даже если задать тегу имя. Тогда уж обычное поле ввода с запретом на ввод.

Говоря о неизбежных багах в коде я имел ввиду min и мах в том числе, но в ином ракурсе.

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

<div id="form" >
    <div class="roword">
        <div class="col-md-3 col-sm-6 col-xs-12 form-col-1">
            <select  form="send" name="color[]">
                <option value="">Выберите цвет</option>
                <option value="1.2">Зеленый</option>
                <option value="1.6">Синий</option>
                <option value="1.8">Красный</option>
            </select>
        </div>
        <div class="col-md-3 col-sm-6 col-xs-12 form-col-2">
            <input form="send" class="minmax" min="40" max="200" type="number" name="width[]">
        </div>
        <div class="col-md-3 col-sm-6 col-xs-12 form-col-3">
            <input form="send" class="minmax" min="40" max="300" type="number" name="height[]">
        </div>
        <div class="col-md-3 col-sm-6 col-xs-12 form-col-4">
            <output></output> <a style="display:none">Удалить</a>
        </div>
    </div>
</div>
<div class="clearfix"></div>
<button>Добавить</button>


Код обслуживающий добавление/удаление полей:

$(function() {
    $('button').click(function() {
        $('div.roword').first() //получаем первый набор полей
                       .clone() //клонируем его
                       .appendTo($('#form')) //добавляем набор в форму
                       .find('select, output').val('') //сбрасываем значения полей 
                       .end() //в начало набора
                       .find('input') //ищем поле ввода
                       .val(function() {
                            return this.min //устанавливаем значение равное минимальному   
                       })
                       .end() //в начало набора
                       .find('a').click(function() { //получаем кнопку удаления полей из формы
                            $(this).closest('.roword').remove() //удаляем добавленное из формы
                       })
                       .show() //делаем видимой кнопку удаления
    });
});


Проблемы неизбежные заложены в полях типа number. В поле можно вводить значение не только кнопками, но и ручным вводом (утомительно набирать максимальное значение с шагом 1). А то, что это поле типа number совсем не означает, что я не могу ввести в нем "абвгд". Вторая проблема, это "что определяет момент расчета"? Если бы это действие запускалось по кнопке "Рассчитать", тогда проблем с проверкой на min бы не было даже при ручном вводе. Но если расчет запускается при каждом изменении ввода и ввод не кнопками, а ручной, то возникает проблема с определением min. Можно конечно навесить таймер, определяя "вроде бы ввод закончен", но это палка о двух концах. С определением max проблем нет.

//обработка ввода, выбора кнопками и выбора в списке
    $('#form').on('change input', 'select, input', function() {
        if(this.type == 'number') { //если поле ввода
            this.value = this.value.replace(/^0|\D/, ''); //вырезаем не цифровые символы и 0 вначале 
            if(this.value.length >= this.max.length && this.max < this.value) this.value = this.max //если значение превышает максимальное             
        }
        //расчет
        //.........
    })


Обработчик определяет - если источник поле number, то удаляет не цифры из набора, сравнивает длину значения и значение с параметрами max. Подобное с min сделать нельзя, так как ввод в поле к примеру 2, еще не означает, что это будет меньше 40, это может быть в итоге 250.

Решить эту проблему можно используя поле не number, а range, тогда необходимость в проверке min/max отпадает (но только для клиента). В этом случае поля описываются так

<input form="send" type="range" min="40" max="300" name="width[]" value="40"> <output>40</output>
и
<input form="send" type="range" min="40" max="200" name="height[]" value="40"> <output>40</output>


В обработчик такой:

$(function() {
    $('button').click(function() {
        $('div.roword').first() //получаем первый набор полей
                       .clone() //клонируем его
                       .appendTo($('#form')) //добавляем набор в форму
                       .find('select').val('') //сбрасываем значение списка
                       .end() //в начало набора
                       .find('input, output') //слайдеры и выводы
                       .val(function(i) {
                            return i == 4 ? '' //очищаем output результата расчета
                                          : this.type == 'range' ? this.min //минимальное значение слайдеру
                                                                 : $(this).prev().attr('min') //отобразить значение слайдера по умолчанию   
                       })
                       .end() //в начало набора
                       .find('a').click(function() { //получаем кнопку удаления полей из формы
                            $(this).closest('.roword').remove() //удаляем добавленное из формы
                       })
                       .show() //делаем видимой кнопку удаления
    })
    //обработка изменения слайдера и выбора в списке
    //событие input в данном случае для отображения значения слайдера непосредственно при перемещении ползунка
    $('#form').on('change input', 'select, input', function() {
        if(this.type == 'range') $(this).next().val(this.value)  //отобразить значение слайдера
        //расчет
        //.........
    })
});

ФедорН 29.06.2017 14:36

laimas, проблема, упомянутая вчера, из-за которой все не работало, - не подключался jquery.
В итоге подключил только через функцию:
<?php
function my_jquery_scripts() {
    wp_deregister_script( 'jquery' );
    wp_register_script( 'jquery', 'https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js');
    wp_enqueue_script( 'jquery' );
}
add_action( 'wp_enqueue_scripts', 'my_jquery_scripts' );
?>


через header.php так и не смог подключить ни одним из способов (причина так мне осталась неясна).

За пояснения снова безмерно благодарю.

Фреймворк jQuery мне показался более простым для понимания, но от понимания логики языка пока далек.

Осталось сделать самую малость- расчет.
Но и тут у меня возникли проблемы :)
Перепробовал много всего, но получил хоть какой-то результат только на этом решении (как понимаю, оно и является одним из/самым простым):

$('#form').on('change input', 'select, input', function() {
        if(this.type == 'range') $(this).next().val(this.value)
 	var h = $('.height').val();
    	var w = $('.width').val();
    	var mySelect = $("#form select option:selected").val();
   		mySelect = (mySelect) ? mySelect : 0; //если ничего не выбрано, правильно? 
    		$('.sum').val(h * w * mySelect);
  })

Поле вывода сделал input (с типом text), как вы и посоветовали. Классы инпутам, конечно, присвоил (не буду снова копировать форму), но результат всегда NaN.

Также еще буду думать над тем, чтобы при площади (height * width) равной или менее 2500 добавлялся доп. коэффициент, как это было сделано в первоначальной версии на JS (h <= 2500 && (c *= 1.1); ).
Для меня понятнее, как это делается через if, но есть варианты проще? (только не пишите за меня решение - сам хочу подумать).

laimas 29.06.2017 16:39

Цитата:

Сообщение от ФедорН
через header.php так и не смог подключить ни одним из способов (причина так мне осталась неясна)

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

Цитата:

Сообщение от ФедорН
Фреймворк jQuery мне показался более простым для понимания

Это не повод всегда обращаться к его услугам когда доступ уже есть и без него. Например, чтобы меньше бродить по набору в коде добавления элементов, строки кода с 06 по 13 можно заменить этим:

.find('select,input,output') //получаем элементы
                       .val(function() { //значения по умолчанию
                            return this.className == 'reset' ? '' 
                                                             : this.type == 'range' 
                                                             ? this.min 
                                                             : this.previousSibling.min 
                       })


В данном случае одной функцией производится установка значений по умолчанию всем добавляемым элементам. Для этого списку и полю отображающему результат расчета добавляется класс reset. С учетом того, что элемент хранящий результат расчета заменен на input, его код будет таким:

<input form="send" class="reset" name="result[]" readonly>


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

<label>Высота:</label>
<input form="send" type="range" min="40" max="200" name="height[]" value="40"><output>40</output>


В противном случае this.previousSibling вернет не input.

Я не выяснял что такое c, не знаю что должно увеличиваться на коэффициент, правьте сами, в примере, это к конечному результату. А расчет, это:

$('#form').on('input', 'select,input', function() {
        if(this.type == 'range') $(this).next().val(this.value)  //отобразить значение слайдера
        //рассчет
        var o = $(this).closest('.roword').find('select,input'), //получить все элементы
            v = o.eq(0).val(), //значение списка 
            w = o.eq(1).val(), //ширина
            h = o.eq(2).val(), //высота
            r = o.last().val(''); //вывод результата, очистить
            if(v) { //если в списке выбрано значение 
                v = v * w * h;
                if(w * h <= 2500) v *= 1.1;
                r.val(v.toFixed(2))
            } 
    })

ФедорН 03.07.2017 11:34

laimas, добрый день.
А с какой целью изначально присваивалось ID форме отправки заказа?

Цитата:

Сообщение от laimas (Сообщение 456021)
Если делать так как я говорил, то <form id="send" class="clearfix callback-form-container" action="{$form_action}" method="post"> - добавляем ID форме.

Получается, есть у меня поля калькулятора, добавил я туда значения , получил стоимость, нажимаю на кнопку отправку заказа, которая по
<?php do_action...

вызывает форму.
У всей формы id="send", а у инпутов калькулятора form="send".
Они уже как-то связаны таким образом?
Теперь мне нужно сделать обработчик, который будет вставлять значения (из полей калькулятора) в конкретное поле формы (отправки заказа)?

laimas 03.07.2017 11:42

Цитата:

Сообщение от ФедорН
с какой целью изначально присваивалось ID форме отправки заказа?

http://htmlbook.ru/html/input/form

Сама форма у вас где-то в панели потом появляется, а поля калькулятора уже на странице и добавляются. Этот атрибут позволяет просто связать поля вне формы с ней без надобности обработки этого скриптами.

ФедорН 03.07.2017 14:52

laimas,
из просмотренных примеров понял, если бы у меня калькулятор был в тегах <form> (но он у меня в div'ах), то форме калькулятора можно было присвоить ID и значения калькулятора могли вставляться, например, в поле textarea формы заказа c атрибутом form="id".

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

Если же получается так, что в моем случае инпуты уже как бы внутри формы заказа, то их вывести (чтобы видел пользователь) как-то можно в отдельное поле формы заказа?

Извиняюсь, вопрос не относится к JS.

laimas 03.07.2017 15:21

Цитата:

Сообщение от ФедорН
и значения этой формы заказа могли вставляться, например, в поле textarea c атрибутом form="id"

Нет, не так. Атрибут полей form связывает их с формой по идентификатору формы, а не с textarea.

Цитата:

Сообщение от ФедорН
вне тегов form есть инпуты с атрибутом form и форма с id, но которая должна получать значения инпутов

Это как раз и обеспечивается этим тегом. Здесь два поля вне формы, но тегом form они связываются с ней. В форме есть только кнопка отправки, которая для примера имеет также имя и значение. Отправление формы собирает в массив все ее поля. Как видите в массиве будут три элемента.

<form id="as" onsubmit="alert(JSON.stringify([].map.call(this.elements, function(e) {
        return e.name + '=' + e.value 
}))); return false">
<button name="sender" value="1">GO</button>
</form>
<input form="as" name="n1" value="2" />
<input form="as" name="n2" value="3" />

ФедорН 03.07.2017 16:56

Получается, пользователь не видит уже свой заказ, когда открывается форма заказа и атрибут form вставить данные (input values из div) в одно из полей формы возможности не дает.

Тогда, как понимаю, можно сделать функцию, где создать массив .map с данными из div_roword input
Преобразовать их в текст: return $(elem).text();
и вывести в поле teaxarea в форме заказа, присвоив ему id="orderItems":
$("#orderItems").text(arr);

laimas 03.07.2017 17:05

Цитата:

Сообщение от ФедорН
Получается, пользователь не видит уже свой заказ

Почему не видит? То что он сам же набирает формой, это что тогда? Форма только регистрирует заказ на сервере, ну или заказчик получает почту с данными заказа (как это обычно и делается). Зачем teaxarea?

Вы либо огород городите, либо .... Я уже говорил, так как вы принимаете заказы от клиента, это мягко говоря действовать "через попу". :) Но если уж так поступать, то элементам полей калькулятора не нужны даже и имена, связывать их с какой-то формой вообще не нужно, так как отправлять их на сервер то зачем?

Ну появилась у вас форма, что там в нее ввели типа личных данных, и в ней же есть teaxarea, в которую по событию отправки формы, получая выбранные значение и расчеты из полей калькулятора, и помещайте их. Это и отправляйте на сервер, если вас это удовлетворяет.

ФедорН 03.07.2017 17:15

Цитата:

Сообщение от laimas (Сообщение 457375)
"через попу". :)

Мягко говоря, да :)

Цитата:

Сообщение от laimas (Сообщение 457375)
Ну появилась у вас форма, что там в нее ввели типа личных данных, и в ней же есть teaxarea, в которую по событию отправки формы, получая выбранные значение и расчеты из полей калькулятора, и помещайте их. Это и отправляйте на сервер, если вас это удовлетворяет.

Вариант подходит, только можно данные в textarea вставлять не по события отправки, а по событию открытия формы (пользователь сразу видит).
Правильно ли я написал, что нужна функция?

laimas 03.07.2017 17:20

Цитата:

Сообщение от ФедорН
можно данные в textarea вставлять не по события отправки

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

ФедорН 04.07.2017 15:06

laimas, добавил функцию в плагин, все работает, но немного не так.
$(function () {
	var orderInfo = '';
	$(".roword input, .roword select").each(function()
	{
		orderInfo += ' x '  + this.value;

	});
	$("#orderItems").html(orderInfo);
});


А именно, необходимо вывести ни value select, а наименование выбранной опции (в моем случае цвет). Не могу найти, как сделать. Попытки реализовать через что-то типа select.attr(), input.attr() успехом не увенчались - все перестает работать.

И еще одна проблема. Если пользователь заполняет одну строку калькулятора, то она вставляется с помощью вышеприведенной функции в поле textarea формы заказа, а если пользователь добавил несколько строк, то всегда добавляется минус одна, по какой-то причине удаляется последняя строка. При вызове попап-формы заказа прямо видно, как последняя срока исчезает. Не подскажите, где копать.

laimas 04.07.2017 15:35

Цитата:

Сообщение от ФедорН
А именно, необходимо вывести ни value select, а наименование выбранной опции

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

if(this.tagName=='SELECT') $(this).text() это и будет текст выбранной опции. К тому же тогда нужны тексты и для других значений, а если так паковать в строку, то в textarea все будет в одну строку. Лучше

var orderInfo = []; и помещая в этот массив одну строку из калькулятора, в textarea записать массив как orderInfo.join('\n').

ФедорН 04.07.2017 19:26

Цитата:

Сообщение от laimas (Сообщение 457536)
Во-первых нужно проверять тогда, что это список, а не поле ввода, вы же коллекцию обоих наборов просматриваете.

if(this.tagName=='SELECT') $(this).text() это и будет текст выбранной опции. К тому же тогда нужны тексты и для других значений, а если так паковать в строку, то в textarea все будет в одну строку. Лучше

var orderInfo = [];
и помещая в этот массив одну строку из калькулятора, в textarea записать массив как orderInfo.join('\n').

сам смысл понятен, с реализацией не все получается.


$(function () {
	var orderInfo = [];
	$(".roword select, .roword input").map(function()
	{
		if(this.tagName=='SELECT')
			orderInfo += $(this).find('option:selected').text();
		else
	 	orderInfo += ' | '  + this.value;

	});

	$("#orderItems").html(orderInfo);
});


пытался сделать по-разному, но это единственный рабочий вариант.
Вы сказали, что всю (одну) строку брать из калькулятора в массив, как понял, это:

$(".roword").map(function()

результат нулевой.

также у меня не работает orderInfo.join('\n')
как понимаю я, если записывать в textarea, то это должно быть:
$("#orderItems").html(orderInfo.join('\n'));

Возможно, не работает из-за некорректной реализации массива.

laimas 04.07.2017 22:41

Цитата:

Сообщение от ФедорН
Возможно, не работает из-за некорректной реализации массива

Нет вообще никакой реализации, это самодеятельность. Нужно формировать строку из значений, а затем ее вставлять методом push() в массив. А чтобы проще было понимать, обходили бы не всю коллекцию элементов, а блоки формы содержащие элементы, получая уже в них коллекцию из четырех элементов, в которой они следуют по порядку под индексами от 0 до 3.

Вам действительно так все пофигу и что там придет от клиента не важно? Наверное же надо добавлять в вывод только тогда, когда пользователем что-то выбрано. Я показывал код, в котором расчет будет только тогда, когда выбрано все необходимое. А значит проверяя значение поля результата расчета, можно решать нужно ли добавлять. Следовательно проверив не пуст ли массив orderInfo, можно будет решать нужна ли отправка формы вообще, или же...? Бог с ним, пусть будет некая доля пофигизма, но не настолько же. :)

$(function () { ... это готовность DOM, если ваш код выполняется значит форма присутствует на странице, она просто не отображается. Поэтому это не добавление "кода в плагин" как вы писали. Переделать это нужно. Лучше так - в обработчике вызывающем эту форму и формировать информацию о заказе, и заблокировав отправку формы (если конечно пофигизм не 100%), снимая блокировку если orderInfo не пуст. Что там за кнопка вызывает форму я не в курсе, ищите, разбирайтесь, а помещение информацию в форму, это:

var orderInfo = $.map($('.roword'), function(e) {
    var o = $(e).find('select,input'); //получить все элементы
    if(o.eq(3).val()) return o.eq(0).children(':selected').text() + ' ' + o.eq(1).val() + 'x' + o.eq(2).val() + ' ' + o.eq(3).val() //если был выбор 
});

if(orderInfo.length) $('textarea').val(orderInfo.join('\n'))

ФедорН 05.07.2017 20:50

laimas, благодарю, все работает. Почему удалялась последняя строка калькулятора, о чем упоминал ранее, тоже разобрался, исправил.

Насчет пофигизма... конечно же, мне не все равно, я обычно разбираюсь в вещах и делаю, как положено. Но случай с программированием - совсем другое - его нельзя освоить за день, неделю, месяц... Тут уже решает приоритет. Протестировать актуальность продукта важнее, чем сделать очень корректный сайт, потратив время, поняв, что он никому не нужен. Если есть посещаемость, то косяки можно отслеживать через вебвизор и допиливать что-то.

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

На данный момент я просто не способен отличить самодеятельность от реализации (по крайней мере, когда я пытаюсь что-то писать сам) в виду отсутствия теоретических и практических знаний. По запросу решения одной задачи находится много примеров в гугле, которые пишутся также людьми с разным уровнем знаний и опыта. И если некоторый код я еще хоть как-то начал разбирать и понимать, то насколько он профессионально написан, увы, нет.

Быть откровенным - изначально я пришел сюда, чтобы решить вышеописанные задачи и сильно не заморачиваться. Но вы так интересно все поясняете, что вчера взялся читать "Выразительный JavaScript". Есть желание разобраться, но нужно подкреплять теорию именно задачами реальными, которые нужны тебе. Лично понял для себя это так.
Мне, новичку, сложно провести корреляцию между задачей "Шахматная доска" и тем, где и в какой реальной ситуации это может пригодиться. На реальной же практике все яснее.
У меня и раньше были вялые попытки освоить язык, теперь я понял, как проще можно это делать.

laimas 06.07.2017 01:22

Цитата:

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

Понимание того, что это есть истина, а это есть ложь, и ценно нам первое из них, это не прерогатива языков программирования. Если вы пишите код надеясь получить результат, по вашему представлению, а получаете undefined, то это может быть следствием незнания Javascript. Но не действовать во вред себе, это вложенное в нас на генетическом уровне тогда, когда мы долбя по голове мамонта камнем, еще не знали, что деградируем и полную приключений жизнь сменим на уныло монотонное долбление клавиш. ;)

Цитата:

Сообщение от ФедорН
На данный момент я просто не способен отличить самодеятельность от реализации (по крайней мере, когда я пытаюсь что-то писать сам) в виду отсутствия теоретических и практических знаний.

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

Я не думаю, что вы напрочь лишены и образного, и логического мышления, и вам никогда не решить простую житейскую задачу. Ваш подъезд навещает разносчик пиццы предлагая ее от фирмы работающей под слоганом "Мы предугадываем ваши желания!".

1) Я не заказывал, а мне принесли, должен ли я быть осторожным?
2) Действительно ли в коробках пицца или все что угодно?
3) Если я возьму предложенное, должен ли я оплатить не проверяя что в коробках?

Решение этой задачи потребует от вас знаний Javascript? Нет конечно. Но ведь и в вашей задаче, которая из жизни переложена в виртуальность все тот же разносчик пиццы. В вашем случае разносчик пиццы - это Интернет. Коробки с пиццей - это форма. Понимая сущность реального "пицционера", прекрасно понимаем, что и виртуальный не обязательно ангел и его коробки всегда наполнены, и наполнены нужным для нас. А значит сценарий вашего приложения обязательно должен иметь условие - я принимаю пиццу (форму) только тогда, когда она в коробке. Разве до этого момента нужны знания конкретного языка программирования? Нет.

1) Предлагаем выбрать цвет и размеры. Надо ли вести расчет если что-то из этого не выбрано? Нет.
2) Надо ли помещать из предложенного в форму если не было расчетов? Нет.
3) Отправлять ли форму если поле заказа не заполнено? Нет.

Конкретизируя детально эти три постулата получаем еще вопросы, и находим на них ответы:

2а) Нужно очищать поле заказа формы перед помещением в него результатов выбора?
а) если не очищаем, придется разбираться в каждой строке заказа (которые уже есть в форме) - она действительна или же пользователь от этого набора отказался.
б) если очищаем, то поле всегда будет иметь только реальные на текущий момент записи заказа.

Значит выбираем б).

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

Цитата:

Сообщение от ФедорН
Протестировать актуальность продукта важнее, чем сделать очень корректный сайт, потратив время, поняв, что он никому не нужен. Если есть посещаемость, то косяки можно отслеживать через вебвизор и допиливать что-то.

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

Веб приложение, это системный блок на сервере, монитор и терминал на клиенте. Если ваше веб приложение, это запрос клиента -> ответ сервера "Привет мир!", то вопросов нет к серверному языку (сценарию) принимающему этот запрос. Но если терминал клиента не просто для ввода, но и для передачи данных от клиента, то это кардинально меняет ситуацию.

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

Когда мы перестали убивать мамонтов и появился Интернет, он был в зачаточном состоянии. Тогда, только отвыкнув от мамонтов, мы воспринимали его как диковинку, и электронные письма в нем "Привет Мери! Приходи к пещере у Большого камня." могли быть лишь слегка дерзкими для юной Мери. Но с тех пор все изменилось, электронная почта теперь не так безобидна и она может быть не только спамом, но и оружием, и порт 25 не только как почтовое отделение, но и местом целенаправленных атак.

Разносчик пиццы всегда за дверью и он никуда не денется, всегда будет стоять за вашими дверями. И если в своей квартире вы отвечаете только за себя, то в квартире арендованной (хосте) вы несете ответственность и за ее мебель, и оборудование предоставленное вам в аренду.

ФедорН 06.07.2017 21:17

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

Мышление у Программистов отличается, бесспорно. Это только положительная сторона.

Да, столь глубоко я в задачу не погружался. Со светлой головой не пытался в нее вникнуть и разобрать. У вас это (я бы сказал, творческий процесс) происходит на автомате. Это ваше.

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

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

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

Флуд разводить не хочется, да и в такой дискуссии истина не родится :)

ФедорН 24.07.2017 13:51

laimas, добрый день. посмею обратиться еще раз :)

При тестировании калькулятора обнаружились проблемы в ie 10, 11 и некоторых мобильных браузерах,а именно:

1. При изменении значение ползунка, не меняется значение output, value всегда остается начальным. В связи с этим, а также неудобством использования ползунка (точный поиск значения с шагом 1) на мобильных устройствах, хотелось бы реализовать рядом с ползунком iput text или number, который будет дублировать значение ползунка,а при вводе числа в input будет меняться значение ползунка, учитывая ограничения, и их автоматическая корректировка, max и min. Пересмотрел примеры, но везде это реализовано через ui, к которому прибегать не хотелось бы (оставив input range). Попытки "колхоза" результата не дали вообще никакого :)

2. При вводе значений, результат в поле input readonly не выводится.
Он может вывестись/измениться, только в том случае если вы установите курсор в это поле, нажмете клавишу на клавиатуре. В противном случае поле всегда статично. не подскажете, в чем причина?

3. не совсем вопрос по теме, но в некоторых случаях также не отображается "направляющая" ползунка, а только передвигающая часть (бегунок).
стилизовал с учетом кроссбраузерности, но так и не могу понять, в чем причина. возможно, скажете, где копать?

Чтобы не искать код, дублирую:

$(function() {
      $('button.addMore').click(function() {
        $('div.roword').first()
            .clone()
            .appendTo($('#form'))
            .find('select').val('')
            .end()
            .find('divinput')
            .val(function(i) {
                return i == 4 ? ''
                    : this.type == 'range' ? this.min
                    : $(this).prev().attr('min')
            })
            .end()
            .find('a').click(function() {
                $(this).closest('.roword').remove()
            })
            .show()
    })

    $('#form').on('input', 'select, input', function() {
        if(this.type == 'range') $(this).next().val(this.value)
        var o = $(this).closest('.roword').find('select,input'), //получить все элементы
            v = o.eq(0).val(), //значение списка
            w = o.eq(1).val(), //ширина
            h = o.eq(2).val(), //высота
            r = o.last().val(''); //вывод результата, очистить
        if(v) { //если в списке выбрано значение
            v = v * w * h;
            if(w * h <= 2399)  v *= 1.1
            else if(w * h >= 2400 && w * h <= 3999) v *= 1.055
            else if(w * h >= 4000 && w * h <= 5399) v *= 1.03;
            else if(w * h >= 5400 && w * h <= 6399) v *= 1.0135;
            r.val(v.toFixed(0))
        }
    })

});

var orderInfo = $.map($('.roword'), function(e) { //вставляет значения из калькулятора в форму заказа

	var o = $(e).find('select,input'); //получить все элементы



	if(o.eq(3).val()) return o.eq(0).children(':selected').text() + ' ' + o.eq(1).val() + 'x' + o.eq(2).val() + ' ' + o.eq(3).val() //если был выбор

});

if(orderInfo.length) $('textarea#orderItems').val(orderInfo.join('\n'))


<div id="form" >
       <div class="roword">
           <div class="col-md-3 col-sm-6 col-xs-12 form-col-1">
               <select  form="send" name="type[]">
                    <option value="">Выберите цвет</option>
                   <option value="1.1">Зеленый</option>
                   <option value="1.4">Синий</option>
                   <option value="1.75">Красный</option>
               </select>
           </div>
           <div class="col-md-3 col-sm-6 col-xs-12 form-col-2">
               <input  form="send" type="range" min="40" max="200" name="height[]" value="40">
              
           </div>
           <div class="col-md-3 col-sm-6 col-xs-12 form-col-3">
               <input form="send" type="range" min="40" max="300" name="width[]" value="40"> <output>40</output>
           </div>
           <div class="col-md-2 col-sm-5 col-xs-10 form-col-4">
               <input class="myPrice" form="send" type="text" name="result[]">
           </div>
           <div class="col-md-1 col-sm-1 col-xs-2 form-col-5">
                <a style="display:none" class="close"></a>
           </div>

       <div class="clearfix"></div>
       </div>
   </div>
   <div class="clearfix addbutton"></div>
   <button class="addMore">Добавить еще</button>

laimas 24.07.2017 15:55

Цитата:

Сообщение от ФедорН
При тестировании калькулятора обнаружились проблемы в ie 10, 11 и некоторых мобильных браузерах

Не охота перечитывать все, но вроде бы упоминание было, что данный код подразумевает поддержку HTML5. А элементы типа number, range, output, это элементы доступные только в браузерах поддерживающих HTML5. Например полная поддержка типа number (кнопки) в FF появилась не так и давно, а по поводу "головной боли", календарей, разработчики вроде бы заявили, что поле типа date они и не собираются поддерживать. Печально, тем более когда в хроме реализован прекрасный и удобный календарь.

Так что если требуется поддержка старых браузеров, мобильных устройств различных, то от новшеств HTML5 придется отказаться. Для того чтобы иметь ползунок на всех устройствах и пишут свое, при этом не обязательно UI нужен, плагинов реализующих ползунок много, ищите в сети, читайте о поддержке его браузерами, выбирайте. А чтобы данный базовый код сделать рабочим под всеми устройствами, это уже тема не для рамок форума вопрос/ответ.

Цитата:

Сообщение от ФедорН
При вводе значений, результат в поле input readonly не выводится.

В каком браузере, да и где в коде поле с таким свойством? Я уже действительно не помню что писал, но в приведенном .find('divinput'), это что?

Цитата:

Сообщение от ФедорН
стилизовал с учетом кроссбраузерности, но так и не могу понять, в чем причина. возможно, скажете, где копать?

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

ФедорН 24.07.2017 18:10

Понял, благодарю. Да, пожалуй, это я упустил момент с html5.
Тогда если можно, только прояснить момент с тем, что не работает автоматический расчет. Не работает в ie 10, ie 11.
И в firefox прежних версий стоимость не обновляется сразу, пока не сдвинешь бегунок. Т.е. вы выбрали все параметры, получили стоимость, потом меняете цвет на более дорогой, но если бегунок не трогали, то стоимость останется от более дешевого цвета, такой попадет в форму заказа.

Цитата:

Сообщение от laimas (Сообщение 459435)
В каком браузере, да и где в коде поле с таким свойством? Я уже действительно не помню что писал, но в приведенном .find('divinput'), это что?

Привожу код с вашими пояснениями:

$(function() {
    $('button').click(function() {
        $('div.roword').first() //получаем первый набор полей
                       .clone() //клонируем его
                       .appendTo($('#form')) //добавляем набор в форму
                       .find('select, output').val('') //сбрасываем значения полей
                       .end() //в начало набора
                       .find('input') //ищем поле ввода
                       .val(function() {
                            return this.min //устанавливаем значение равное минимальному  
                       })
                       .end() //в начало набора
                       .find('a').click(function() { //получаем кнопку удаления полей из формы
                            $(this).closest('.roword').remove() //удаляем добавленное из формы
                       })
                       .show() //делаем видимой кнопку удаления
    });
});


поле вывода результата
<input class="myPrice" form="send" type="text" name="result[]" readonly>


Правда, тогда может и логично, если ie не знаком с range, то он и не может считать результат - просто не поминает, что такое value из range.

laimas 24.07.2017 18:55

Нет, IE11 поддерживает range, но событие input для всех нет. А вот элемент output IE не поддерживает. Можно заменить output на span, а обработчик расчета дополнить событием change, то есть вот так будут выглядеть его первые строки теперь:

$('#form').on('input change', 'select,input', function() {
        if(this.type == 'range') $(this).next().text(this.value)  //отобразить значение слайдера (теперь это span) 
        //код далее


Судя по этому class="col-md-3 col-sm-6 col-xs-12 form-col-1" используется бутсрап, это значит учитывается и мобильные устройства, а в нем есть все свое, включая и плагин range.

PS. О проблеме с readonly так и не понял.

ФедорН 24.07.2017 19:27

Цитата:

Сообщение от laimas (Сообщение 459448)
Нет, IE11 поддерживает range, но событие input для всех нет. А вот элемент output IE не поддерживает. Можно заменить output на span, а обработчик расчета дополнить событием change, то есть вот так будут выглядеть его первые строки теперь:

Событием change дополнил и как раз разрешилась проблема с input readonly, которая:
Цитата:

Сообщение от laimas (Сообщение 459448)
PS. О проблеме с readonly так и не понял.

Результат вычисления стал динамически изменяться.

А вот ситуацию с output, который выводит значение input range это не изменило, даже наоборот.

Я добавил change, заменил <output>40</output> на <span>40</span>, даже в последней версии chrome данное значение перестало работать - всегда (при изменении положения ползунка) отображается минимальный value, т.е. 40.

laimas 24.07.2017 19:56

Цитата:

Сообщение от ФедорН
даже в последней версии chrome данное значение перестало работать

Что-то делается не так, вот все, работает и в хроме, и ослике:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(function() {

    $('button').click(function() {
        $('div.roword').first()
                       .clone()
                       .appendTo($('#form'))
                       .find('select').val('')
                       .end()
                       .find('input, output')
                       .val(function(i) {
                            return i == 4 ? '' : this.type == 'range' ? this.min : $(this).prev().attr('min')  
                       })
                       .end()
                       .find('a').click(function() {
                            $(this).closest('.roword').remove()
                       })
                       .show()
    })
    
    //обработка изменения слайдера и выбора в списке
    $('#form').on('input change', 'select,input', function() {
        if(this.type == 'range') $(this).next().text(this.value)  //отобразить значение слайдера    
        //рассчет
        var o = $(this).closest('.roword').find('select,input'),
            v = o.eq(0).val(),
            w = o.eq(1).val(),
            h = o.eq(2).val(),
            r = o.last().val('');
            if(v) { 
                v = v * w * h;
                if(w * h <= 2399)  v *= 1.1
                else if(w * h >= 2400 && w * h <= 3999) v *= 1.055
                else if(w * h >= 4000 && w * h <= 5399) v *= 1.03;
                else if(w * h >= 5400 && w * h <= 6399) v *= 1.0135;
                r.val(v.toFixed())
            }
    })

});
</script> 
</head>
<body>

<div id="form" >
    <div class="roword">
        <div class="col-md-3 col-sm-6 col-xs-12 form-col-1">
            <select  form="send" name="color[]">
                <option value="">Выберите цвет</option>
                <option value="1.2">Зеленый</option>
                <option value="1.6">Синий</option>
                <option value="1.8">Красный</option>
            </select>
        </div>
        <div class="col-md-3 col-sm-6 col-xs-12 form-col-2">
            <input form="send" type="range" min="40" max="300" name="width[]" value="40"><span>40</span>
        </div>
        <div class="col-md-3 col-sm-6 col-xs-12 form-col-3">
            <input form="send" type="range" min="40" max="200" name="height[]" value="40"><span>40</span>
        </div>
        <div class="col-md-3 col-sm-6 col-xs-12 form-col-4">
            <input class="myPrice" form="send" type="text" name="result[]" readonly> <a style="display:none">Удалить</a>
        </div>
    </div>
</div>
<div class="clearfix"></div>
<button>Добавить</button>

</body>
</html>

laimas 25.07.2017 06:30

ФедорН,
забыл, в расчетах под span изменил, а в клонировании нет, должно быть так:

$('button').click(function() {
        $('div.roword').first()
                       .clone()
                       .appendTo($('#form'))
                       .find('select,[type=text]').val('')
                       .end()
                       .find('input')
                       .val(function() {
                            return this.min  
                       })
                       .end()
                       .find('span').text(function() {
                            return $(this).prev()[0].min
                       })
                       .end()
                       .find('a').click(function() {
                            $(this).closest('.roword').remove()
                       })
                       .show()
    });

ФедорН 25.07.2017 09:38

laimas, действительно, это у меня была ошибка в коде скрипта.
Все работает. Спасибо.

Можно еще вопрос.
Каждой строке списка товаров в форме заказа хотелось бы в начале присвоить номер.

var orderInfo = $.map($('.roword'), function(e) { //вставляет значения из калькулятора в форму заказа
		
var i = $(".roword"),
u = +i.val();
	
var o = $(e).find('select,input'); //получить все элементы

	if(o.eq(3).val()) return  u+'.' + ' ' + o.eq(0).children(':selected').text() + ' ' + o.eq(1).val() + 'x' + o.eq(2).val() + ' ' + o.eq(3).val() //если был выбор

});

if(orderInfo.length) $('textarea#orderItems').val(orderInfo.join('\n'))


Насколько удалось накопать, самый понятный вариант - когда мы присваиваем номер каждому div .roword.
Добавилvar i = $(".roword"),
u = +i.val(); и возврат значения u в строке
, но нумерация строк начинается с нуля, при попытке добавить счетчик или начать с .val(+1) получаю NaN. Почему значение получается не числовое? Как понимаю, вначале я привожу как раз u к числовому значению.

laimas 25.07.2017 09:41

Зачем номер и для чего?

ФедорН 25.07.2017 09:56

Цитата:

Сообщение от laimas (Сообщение 459495)
Зачем номер и для чего?

Напомню:
У меня получается так, что на странице клиент может добавить в калькулятор несколько позиций, далее открывает форму заказа и эти позиции, каждая в виде отдельной строки, добавляются в поле textarea.
Высота textarea ограничена, прокрутка не сильно удобна, при просмотре позиций (особенно если несколько одинаковых) легко сбиться. Я смотрел, как сделать поле textarea "резиновым" (скрипт впечатляющий). Также "примерял" div contenteditable, не впечатлил (и оформить корректно его мне не удалось). Поэтому я решил остановиться на том, чтобы просто пронумеровать строки, так по цифрам сбиться будет невозможно.

laimas 25.07.2017 10:11

Цитата:

Сообщение от ФедорН
Поэтому я решил остановиться на том, чтобы просто пронумеровать строки, так по цифрам сбиться будет невозможно.

Вы разрешаете пользователю добавить но не заполняя отправить? Думаю нет, а следовательно все что выбрано будет по-порядку. Чем может помочь нумерация?

Если уж так охота пронумеровать в итоге, то есть в textarea, то методы $.map, $each и прочие, первым аргументом в функцию передают индекс элемента. Добавляйте к нему 1, получите нумерацию от 1 до ...

ФедорН 25.07.2017 10:39

Цитата:

Сообщение от laimas (Сообщение 459498)
Если уж так охота пронумеровать в итоге, то есть в textarea, то методы $.map, $each и прочие, первым аргументом в функцию передают индекс элемента. Добавляйте к нему 1, получите нумерацию от 1 до ...

Спасибо! Оказалось, так просто.

laimas 25.07.2017 10:53

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

$('div.roword').filter(function() {
    return !$(this).find('select').val()
}).remove();


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

ФедорН 25.07.2017 21:29

Цитата:

Сообщение от laimas (Сообщение 459502)
Более полезным было бы удалять из набора не выбранные опции, а так как фактически это задается выбором в списке, то те, в которых нет выбора в нем. Делать это нужно по вызову формы

$('div.roword').filter(function() {
    return !$(this).find('select').val()
}).remove();

Благодарю. Согласен, полезная функция.
Я сначала ее в калькулятор запихал, естественно, первая строка при загрузке сразу удалялась :) потом уже в форму заказа добавил, все ок. но как понял, теоретически, если реализовать как-то через .onclick, то возможно было и в калькулятор добавить? (это сугубо для понимания. код не нужен).

Цитата:

Сообщение от laimas (Сообщение 459502)
А нумерация чисто для красоты, вряд ли пользователь будет запоминать под каким номером он чего-то набрал, да и так ли это важно.

Нет, нет, запоминать ничего не нужно.

Грубо на примере:


Заказали вы 10 Полей с исходным текстом, по высоте texarea весь список не отображается (максимум видно 2 позиции за раз), нужно пролистывать стрелками прокрутки. Пересчитать таким образом, что их 10, будет довольно проблематично, учитывая, что все они одинаковы.
А так они пронумерованы, вы сразу видите:
1. Поле с исходным текстом
...
10. Поле с исходным текстом

Это и всего лишь имелось в виду.

laimas 25.07.2017 22:14

Цитата:

Сообщение от ФедорН
Я сначала ее в калькулятор запихал, естественно, первая строка при загрузке сразу удалялась

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

$('div.roword').not(':first').filter(function() {
           return !$(this).find('select').val()
        })
        .remove()
        .end()


Это коллекция, в которой все после первого набора заполнены. Заполнено ли все в первой неизвестно, требуется проверка.

ФедорН 26.07.2017 20:26

Цитата:

Сообщение от laimas (Сообщение 459606)
Все верно, она и должна удаляться так как это пример без учета того, что элементы первого набора удалять нельзя. Если можно отменить отправление формы и вернуться к набору, то удалив первый набор полей, добавить новые клонированием уже нельзя. Удалять незаполненные, но кроме первой:

Понял. Поправил. Все ок.

laimas 26.07.2017 20:37

Цитата:

Сообщение от ФедорН
Все ок.

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

Поле можно добавлять используя ранее заготовленный шаблон, который описан в переменной или хранится как данные в атрибуте кнопки Добавить:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<style>
.myPrice {
    border: none;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(function() {
    
    $('button').click(function() {
       $($(this).data('ins')).appendTo($('#form'))
                             .find('.myPrice').focus(function() {
                                    this.blur()
                             })
                             .end()
                             .find('a').click(function() {
                                    $(this).closest('.roword').remove()
                             })
    });
    
    //обработка изменения слайдера и выбора в списке
    $('#form').on('input change', 'select,input', function() {
        if(this.type == 'range') $(this).next().text(this.value)  //отобразить значение слайдера    
        //рассчет
        var o = $(this).closest('.roword').find('select,input'),
            v = o.eq(0).val(),
            w = o.eq(1).val(),
            h = o.eq(2).val(),
            r = o.last().val('');
            if(v) { 
                v = v * w * h;
                if(w * h <= 2399)  v *= 1.1
                else if(w * h >= 2400 && w * h <= 3999) v *= 1.055
                else if(w * h >= 4000 && w * h <= 5399) v *= 1.03;
                else if(w * h >= 5400 && w * h <= 6399) v *= 1.0135;
                r.val(v.toFixed())
            }
    });
    
    $('a').click(function() {
        $('div.roword').filter(function() {
            return !$(this).find('select').val()
        }).remove();
                
        var res = $.map($('div.roword'), function(e, i) {
                            return i+1 + '. ' + $.map($(e).find('select,input'), function(e) {
                                return e.value
                        }).join(', ');
                  }).join('\n');
        
        if(res) {
            $('textarea').val(res);
            $('button').prop('disabled', 0);
        }
    })

});
</script> 
</head>
<body>

<div id="form"></div>

<div class="clearfix"></div>
<button data-ins='<div class="roword"><div class="col-md-3 col-sm-6 col-xs-12 form-col-1"><select>
<option value="">Выберите цвет</option><option value="1.2">Зеленый</option><option value="1.6">Синий</option><option value="1.8">Красный</option></select>
</div><div class="col-md-3 col-sm-6 col-xs-12 form-col-2"><input type="range" min="40" max="300" value="40"><span>40</span></div>
<div class="col-md-3 col-sm-6 col-xs-12 form-col-3"><input type="range" min="40" max="200" value="40"><span>40</span></div>
<div class="col-md-3 col-sm-6 col-xs-12 form-col-4"><input class="myPrice" type="text" readonly> <a>Удалить</a></div></div>'>Добавить</button>

<div><textarea></textarea></div>
<a>Send</a>
</body>
</html>

ФедорН 03.08.2017 09:32

laimas, прошу прощения, только сейчас увидел ваше последнее сообщение. Вы имели в виду, что первая строка требует проверки перед тем, как добавить следующую или же перед тем, как перейти к форме заказа?
Но что-то в коде не так: перестали работать калькулятор и кнопка "добавить", с первой же строки калькулятора появилась не кликабельная "удалить".
В html были несколько ошибок (видимо, образовались в процессе копирования): съехал <button data-ins=' и <div class="clearfix"></div>, и как понимаю, это лишний кусок: <div><textarea></textarea></div>
<a>Send</a>
Это я поправил. Но скрипт не могу.


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