Я нашел вопросы, которые обсуждают с использованием мультиселекции, основанной на другой мультиселекте , , клонирующей строку формы и , динамически обновляемой опции выбора . Но нет вопросов, на которые можно ответить, как сделать все три вместе .
В моем конкретном примере c у меня есть два раскрывающихся списка рядом - operation_key
и operation_value
. Исходя из выбора пользователя для operation_key
, он должен видеть либо обычный (одиночный) выбор, либо множественный выбор и иметь соответствующие параметры, динамически заполняемые в соответствующем раскрывающемся списке operation_value
.
Вот отображение того, как оно должно работать:
+---------------+---------------------------------+---------------------------------------+
| Operation Key | Operation Value - Dropdown Type | Operation Value - Dropdown Options |
+---------------+---------------------------------+---------------------------------------+
| continents | multiple | North America, South America, Europe |
| languages | multiple | English, French, Spanish |
| eye_color | single | Brown, Blue, Green, Hazel |
| age | single | 18-24, 25-32, 33-40, >41 |
+---------------+---------------------------------+---------------------------------------+
Я соединил код из различных примеров и придумал следующее:
// clone functionality
const regex = /^(.+?)(\d+)$/i;
let cloneIndex = $(".operation").length;
function setIndex(elements) {
elements.each(function(index, element) {
// set the appropriate index on the cloned element (not working)
$(element).find("select.operation_keys").attr("name", "operation_keys[" + index + "]");
$(element).find("select.operation_values").attr("name", "operation_values[" + index + "]");
});
}
function clone() {
let $removeButton = $(this).closest(".actions").find(".remove-operation");
let $closestOperation = $(this).closest(".actions").prev(".operation").first();
$removeButton.show();
$closestOperation.clone()
.insertAfter($closestOperation).attr("id", "operation-" + cloneIndex)
.find("*")
.each(function() {
let id = this.id || "";
let match = id.match(regex) || [];
if (match.length == 3) {
this.id = match[1] + '-' + (cloneIndex);
}
});
cloneIndex++;
let $Operations = $(this).closest(".operation-parent").find(".operation");
setIndex($Operations);
}
function remove() {
$(this).closest(".actions").prev(".operation").remove();
let $Operations = $(this).closest(".operation-parent").find(".operation");
setIndex($Operations);
let totalElements = $(this).closest(".operation-parent").find(".operation").length;
if (totalElements === 1) {
$(this).hide();
}
cloneIndex--;
}
$(".add-operation").on("click", clone);
$(".remove-operation").on("click", remove);
// select logic
function buildSelect(operationKey) {
let result = {};
switch (operationKey) {
case 'continents':
result['operationValues'] = ['North America', 'South America', 'Europe'];
result['type'] = 'multiple';
break;
case 'languages':
result['operationValues'] = ['English', 'French', 'Spanish'];
result['type'] = 'multiple';
break;
case 'eye_color':
result['operationValues'] = ['Brown', 'Blue', 'Green', 'Hazel'];
result['type'] = 'single';
break;
case 'age':
result['operationValues'] = ['18-24', '25-32', '33-40', '>41'];
result['type'] = 'single';
break;
}
return result;
}
$('.operation-keys').on('change', function() {
let operationKey = $(this).val()
// get the nearest value dropdown element (not working)
let valueSelect = $(this).closest('.operation-values');
// get the values + type of select we should populate
let result = buildSelect(operationKey);
// set the select type, if needed
if (result['type'] == 'multiple') {
valueSelect.attr("multiple", "multiple")
}
// populate the values (not working)
let options = result['operationValues'];
for (var i = 0; i < options.length; i++) {
valueSelect.options.add(new Option(option.toLowerCase(), option));
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://github.com/davidstutz/bootstrap-multiselect/blob/master/dist/css/bootstrap-multiselect.css" type="text/css" />
<div class="form-group row">
<label class="col-4">Operation Key</label>
<label class="col-6">Operation Value</label>
</div>
<div class="form-group">
<div class="operation-parent row">
<div class="col-8 operation">
<div class="row">
<div class="col-6">
<select class="form-control form-control-lg operation-keys" name="operation_keys[]">
<option value="continents">Continents Visited</option>
<option value="languages">Languages Spoken</option>
<option value="eye_color">Eye Color</option>
<option value="age">Age</option>
</select>
</div>
<div class="col-6">
<select class="form-control form-control-lg mb-30 operation-values" name="operation_values[]">
</select>
</div>
</div>
</div>
<div class="col-2 actions">
<a class="btn btn-alt-success add-operation">+</a>
<a class="btn btn-alt-danger remove-operation" style="display:none;">-</a>
</div>
</div>
<script type="text/javascript" src="https://github.com/davidstutz/bootstrap-multiselect/blob/master/dist/js/bootstrap-multiselect.js"></script>
JSFiddle: https://jsfiddle.net/vs6oLugy/
Есть несколько проблем:
1) Функция setIndex()
должна динамически обновлять имена клонированных полей .operation_keys
и .operation_values
. Например, operation_keys[1]
, operation_values[1]
, operation_keys[2]
, operation_values[2]
, et c. По какой-то причине это не работает. Я предполагаю, что это потому, что $(element).find("select.operation_keys")
неправильно нацеливает элемент, но я не могу понять, почему это не так.
2) Остальная часть лога c, которая находит и обновляет соответствующий .operation_values
выпадающий с соответствующим типом (обычный выбор или множественный выбор) и устанавливает доступные варианты / опции не работает. Я думаю, что проблема в строке, которая нацеливается на раскрывающийся список:
let valueSelect = $(this).closest('.operation-values');
Каждый из селекторов находится внутри родительского .col-6
div, поэтому, возможно, $(this).closest()
isn ' в состоянии пройти вверх через дерево DOM? Хотя я не уверен, что должно измениться, чтобы эта часть работала. Я попытался изучить родные элементы и сначала получить родительский элемент, но ни один из них не сработал.
3) Когда клонируется строка, я не уверен, как скрыть второй (самый правый) раскрывающийся список (operation_value
), чтобы побудить пользователя сначала сделать выбор в левом раскрывающемся списке (operation_key
). Когда строка клонируется, строка, из которой она была клонирована, предположительно, могла иметь оба выпадающих списка, поэтому достаточно ли безопасно просто вызывать .hide()
для нового самого правого выпадающего списка, созданного функцией clone()
?
Любая помощь очень ценится!