powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / HTML, JavaScript, VBScript, CSS [игнор отключен] [закрыт для гостей] / js select - исключить каскадные события для onchange
7 сообщений из 7, страница 1 из 1
js select - исключить каскадные события для onchange
    #39931471
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На форме есть несколько выпадающих списков.
При выборе значения в одном из списков содержимое следующего списка обновляется в зависимости от выбранного значения.
Например, если в списке 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
js select - исключить каскадные события для onchange
    #39931609
Фотография krvsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B. , вместо такого долгого объяснения лучше бы сделал тестовый пример...
На нем было бы понятно, что у тебя происходит и не делать пример самому, чтобы что-то показать тебе...
...
Рейтинг: 0 / 0
js select - исключить каскадные события для onchange
    #39931716
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Как-то так: https://jsfiddle.net/n85d62pL/ (в jsfiddle атрибут onchange почему-то не работает, продублировал его через addEventListener).
Но тут почему-то каскадного срабатывания события не наблюдаю (при задании selectedIndex событие change не срабатывает).
Код в примере упрощен, но идентичен моему.
...
Рейтинг: 0 / 0
js select - исключить каскадные события для onchange
    #39932002
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Каскадного срабатывания событий добиться не получается, видимо у меня какая-то малозаметная ошибка была.
Но какая-то странность все равно остается.
Сделать пример на 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
js select - исключить каскадные события для onchange
    #39932008
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нашел причину.
Нужно было обнулять выбранные тарифы при смене типа и до вызова tariff_load.
...
Рейтинг: 0 / 0
js select - исключить каскадные события для onchange
    #39932048
Фотография krvsa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B. , так ты решил свою проблемку?

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


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