Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / HTML, JavaScript, VBScript, CSS [игнор отключен] [закрыт для гостей] / js select - исключить каскадные события для onchange / 7 сообщений из 7, страница 1 из 1
27.02.2020, 10:05
    #39931471
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
js select - исключить каскадные события для onchange
На форме есть несколько выпадающих списков.
При выборе значения в одном из списков содержимое следующего списка обновляется в зависимости от выбранного значения.
Например, если в списке A выбрано значение A1, то в списке B доступны значения B1, B2. Если в списке A выбрано значение A2, то в списке B доступны значения B3, B4.
У всех списков в onchange задан один и тот же обработчик, onchange="item_change(this)".
В документации указано, что onchange срабатывает при интерактивных пользовательских действиях.
Но по факту оказывается, что событие каскадно срабатывает в том числе и тогда, когда в обработчике меняется selectedIndex.
Как можно исключить каскадное срабатывание обработчика?
Я пока делаю так:
Код: javascript
1.
2.
3.
4.
5.
6.
7.
function item_change($el=null)
{
	if (typeof item_change.busy != 'undefined') return;
	item_change.busy = true;
	...
	delete item_change.busy;
}


Но мне кажется, что должен быть более "нативный" способ.
...
Рейтинг: 0 / 0
27.02.2020, 12:26
    #39931609
krvsa
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
js select - исключить каскадные события для onchange
Alibek B. , вместо такого долгого объяснения лучше бы сделал тестовый пример...
На нем было бы понятно, что у тебя происходит и не делать пример самому, чтобы что-то показать тебе...
...
Рейтинг: 0 / 0
27.02.2020, 14:27
    #39931716
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
js select - исключить каскадные события для onchange
Как-то так: https://jsfiddle.net/n85d62pL/ (в jsfiddle атрибут onchange почему-то не работает, продублировал его через addEventListener).
Но тут почему-то каскадного срабатывания события не наблюдаю (при задании selectedIndex событие change не срабатывает).
Код в примере упрощен, но идентичен моему.
...
Рейтинг: 0 / 0
27.02.2020, 22:11
    #39932002
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
js select - исключить каскадные события для onchange
Каскадного срабатывания событий добиться не получается, видимо у меня какая-то малозаметная ошибка была.
Но какая-то странность все равно остается.
Сделать пример на jsfiddle не получается, там почему-то игнорируются атрибуты onchange.
Но можно сохранить в HTML приложенный код и открыть его в браузере.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>

<body>
<script>
function ready() {
	tariff_change();
}
document.addEventListener("DOMContentLoaded", ready);
</script>
<script type="text/javascript">
'use strict';

function escapeHtml($text)
{
	if ($text)
	{
		$text = $text.replace(/&/g, "&");
		$text = $text.replace(/</g, "<");
		$text = $text.replace(/>/g, ">");
		$text = $text.replace(/"/g, """);
		$text = $text.replace(/'/g, "'");
	}
	else
	{
		$text = '';
	}
	return $text;
}

function formatCurrency($value)
{
	$value = $value.toFixed(2) + '';
	let $rest = '00';
	let $x = $value.indexOf('.');
	if ($x >= 0)
	{
		$rest = $value.substring($x+1);
		$value = $value.substring(0, $x);
	}
	$value = $value.replace(/(.)(?=(\d{3})+$)/g,'$1\'');
	return $value + ',' + $rest;
}

function tariff_find($tariff)
{
	let $type = document.getElementById('fldType').value;
	switch($type.substring(0,2))
	{
		case '':
			$type = 0;
			break;
		case 'ФЛ':
			$type = 1;
			break;
		case 'ИП':
			$type = 2;
			break;
		case 'ЮЛ':
			$type = 3;
			break;
		default:
			$type = -1;
			break;
	}
	let $found = null;
	for (let $il = 0; $il < $cache['tariff'].length ; $il++)
	{
		let $line = $cache['tariff'][$il];
		if ($line.items)
		{
			for (let $in = 0; $in < $line.items.length ; $in++)
			{
				let $name = $line.items[$in];
				if ($name.variants)
				{
					for (let $iv = 0; $iv < $name.variants.length ; $iv++)
					{
						let $item = $name.variants[$iv];
						if ($tariff == $item.id)
						{
							$found = {"active": (!$line.type || ($line.type.indexOf($type)>=0)), "id": $item.id, "line": $line.line, "lineIndex": $il, "name": $name.name, "nameIndex": $in, "item": $item.extra, "itemIndex": $iv, "price": $item.price, "description": $name.description};
						}
						if ($found) break;
					}
				}
				else
				{
					if ($tariff == $name.id)
					{
						$found = {"active": (!$line.type || ($line.type.indexOf($type)>=0)), "id": $name.id, "line": $line.line, "lineIndex": $il, "name": $name.name, "nameIndex": $in, "item": $name.extra, "itemIndex": null, "price": $name.price, "description": $name.description};
					}
				}
				if ($found) break;
			}
		}
		if ($found) break;
	}
	return $found;
}

function tariff_load($type=null, $line=null, $name=null, $item=null)
{
	let $id = null;
	let $fldLine = document.forms["form-new"].elements["tariff_line"];
	let $fldName = document.forms["form-new"].elements["tariff_name"];
	let $fldItem = document.forms["form-new"].elements["tariff_item"];
	if (!$line) $line = $fldLine.value;
	if (!$name) $name = $fldName.value;
	if (!$item) $item = $fldItem.value;
	$fldLine.options.length = 0;
	$fldName.options.length = 0;
	$fldItem.options.length = 0;
	{
		let $ll = $cache['tariff'];
		$fldLine.append(new Option());
		for (let $i = 0; $i < $ll.length ; $i++)
		{
			let $l = $ll[$i];
			if (!$l.type || ($l.type.indexOf($type)>=0))
			{
				$fldLine.append(new Option($l.line, $l.line));
			}
			if ($line == $l.line)
			{
				$fldLine.selectedIndex = $i+1;
				let $ln = $l.items;
				$fldName.append(new Option());
				for (let $i = 0; $i < $ln.length ; $i++)
				{
					let $l = $ln[$i];
					$fldName.append(new Option($l.name, $l.name));
					if ($name == $l.name)
					{
						$fldName.selectedIndex = $i+1;
						if ($l.variants)
						{
							let $li = $l.variants;
							$fldItem.append(new Option());
							for (let $i = 0; $i < $li.length ; $i++)
							{
								let $l = $li[$i];
								$fldItem.append(new Option($l.extra, $l.extra));
								if ($item == $l.extra)
								{
									$fldItem.selectedIndex = $i+1;
									$id = $l.id;
								}
							}
						}
						else
						{
							$id = $l.id;
							$fldItem.append(new Option($l.extra, $l.extra));
						}
					}
				}
			}
		}
	}
	return $id;
}

function tariff_change($el=null)
{
	let $tariff = document.getElementById('fldTariff').value;
	let $type = document.getElementById('fldType').value;
	switch($type.substring(0,2))
	{
		case '':
			$type = 0;
			break;
		case 'ФЛ':
			$type = 1;
			break;
		case 'ИП':
			$type = 2;
			break;
		case 'ЮЛ':
			$type = 3;
			break;
		default:
			$type = -1;
			break;
	}
	let $ro = document.getElementById('fldTariffLine').readOnly;
	if (!$ro)
	{
		$tariff = tariff_load($type);
	}
	let $found = tariff_find($tariff);
	if ($found && !$found.active && !$ro)
	{
		$found = null;
		$tariff = null;
	}
	let $head = document.getElementById('fldTariffInfoTitle');
	let $body = document.getElementById('fldTariffInfoContent');
	if ($found)
	{
		$head.innerHTML = ''+escapeHtml($found.line)+' '+escapeHtml($found.name);
		$body.innerHTML = 'Абонплата: <var>'+formatCurrency($found.price)+'</var> / '+$found.item+'<br>'+escapeHtml($found.description);
		$head.classList.remove('d-none');
	}
	else
	{
		if ($tariff)
		{
			$head.innerHTML = 'Тариф #'+$tariff;
			$body.innerHTML = '<em class="text-muted">Подробная информация о тарифе отсутствует.</em>';
			$head.classList.remove('d-none');
		}
		else
		{
			$head.innerHTML = '';
			$body.innerHTML = '<em class="text-muted">Выберите тариф, чтобы просмотреть подробную информацию.</em>';
			$head.classList.add('d-none');
		}
	}
}
</script>
<script type="text/javascript">
var $cache = {};
$cache['tariff'] = [{"line":"Группа1","type":[1],"items":[{"name":"Начальный","description":"...","variants":[{"id":5092,"extra":"3 месяца","price":2070},{"id":5052,"extra":"6 месяцев","price":4140},{"id":5054,"extra":"12 месяцев","price":8280}]},{"name":"Популярный","description":"...","variants":[{"id":5093,"extra":"3 месяца","price":2445},{"id":5094,"extra":"6 месяцев","price":4890},{"id":5096,"extra":"12 месяцев","price":9780}]},{"name":"Премиум","description":"...","variants":[{"id":5212,"extra":"3 месяца","price":3010},{"id":5213,"extra":"6 месяцев","price":5850},{"id":5214,"extra":"12 месяцев","price":11160}]},{"name":"Премиум+","description":"...","variants":[{"id":5215,"extra":"3 месяца","price":3385},{"id":5216,"extra":"6 месяцев","price":6600},{"id":5217,"extra":"12 месяцев","price":12660}]}]},{"line":"Группа2","type":[1],"items":[{"id":5016,"name":"Начальный","price":725,"description":"...","extra":"Ежемесячно"},{"id":5017,"name":"Популярный","price":850,"description":"...","extra":"Ежемесячно"},{"id":5253,"name":"Премиум","price":1075,"description":"...","extra":"Ежемесячно"},{"id":5293,"name":"Премиум+","price":1200,"description":"...","extra":"Ежемесячно"}]}];
</script>

<form name="form-new">
	<div class="form-row">
		<div class="form-group col-md-4">
			<label for="fldType">Тип:</label>
			<select class="form-control" id="fldType" name="type" onchange="tariff_change(this)">
				<option selected></option>
				<option>ФЛ (ч/д)</option>
				<option>ФЛ (МКД)</option>
				<option>ИП (ТЦ)</option>
				<option>ИП</option>
				<option>ЮЛ (ТЦ)</option>
				<option>ЮЛ</option>
			</select>
		</div>
	</div>
	<hr>
	<fieldset class="form-group">
		<div class="form-row">
			<div class="form-group col-md-4">
				<label for="fldTariffLine">Группа тарифов:</label>
				<select class="form-control" id="fldTariffLine" name="tariff_line" onchange="tariff_change(this)">
					<option selected></option>
				</select>
			</div>
			<div class="form-group col-md-4">
				<label for="fldTariffName">Тарифный план:</label>
				<select class="form-control" id="fldTariffName" name="tariff_name" onchange="tariff_change(this)">
					<option selected></option>
				</select>
			</div>
			<div class="form-group col-md-4">
				<label for="fldTariffItem">Вариант:</label>
				<select class="form-control" id="fldTariffItem" name="tariff_item" onchange="tariff_change(this)">
					<option selected></option>
				</select>
			</div>
		</div>
		<input type="hidden" id="fldTariff" value="5212" name="tariff">
		<div class="card border-secondary" id="fldTariffInfo">
			<div class="card-body text-secondary">
				<h5 class="card-title d-none" id="fldTariffInfoTitle"></h5>
				<p class="card-text" id="fldTariffInfoContent"></p>
			</div>
		</div>
	</fieldset>
</form>

</body>
</html>


Пример странности:
1. Выбираем тип ФЛ.
2. Выбираем группу, тариф и вариант.
3. По выбранному тарифу выводится подробная информация.
4. Выбираем тип ИП.

При смене типа список с группами тарифов обнуляется (поскольку в кеше нет соответствующих тарифов).
Но списки с тарифами и вариантами почему-то остаются без изменений, несмотря на выполняемый .options.length = 0.
Не могу понять, почему так.
...
Рейтинг: 0 / 0
27.02.2020, 22:42
    #39932008
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
js select - исключить каскадные события для onchange
Нашел причину.
Нужно было обнулять выбранные тарифы при смене типа и до вызова tariff_load.
...
Рейтинг: 0 / 0
28.02.2020, 07:35
    #39932048
krvsa
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
js select - исключить каскадные события для onchange
Alibek B. , так ты решил свою проблемку?

Я бы не стал для таких целей использовать единый обработчик события... Т.к., все равно, придется узнавать на каком элементе произошло событие... И действия будут явно разные...
...
Рейтинг: 0 / 0
28.02.2020, 07:39
    #39932049
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
js select - исключить каскадные события для onchange
Да, переписал заново, теперь работает правильно.
До этого обработчик вызывался каскадно, уж не знаю почему.
Элементы разные, но обработка однотипна - при изменении данных сбросить значения следующих полей.
...
Рейтинг: 0 / 0
Форумы / HTML, JavaScript, VBScript, CSS [игнор отключен] [закрыт для гостей] / js select - исключить каскадные события для onchange / 7 сообщений из 7, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]