У меня есть Аналитический паралич, и мне нужен ввод. Я могу изменить SQL-запрос, JavaScript, И / или контроллер CFML (весь код размещен ниже).
Все, что я хочу сделать, это заполнить поле выбора параметрами и оптгруппами. Optgroup - это то, что меня сбивает с толку.
Sql довольно прост и выглядит так:
SELECT
g.groupID,
g.groupLabel,
u.unitLabel,
u.unitID
FROM
group g
LEFT JOIN unit u ON g.groupID = u.groupID
И цикл (ы) CFML выглядит следующим образом (я считаю, что здесь также необходимо выполнить настройку с некоторой логикой, например, если thisGroupLabel соответствует preGroupLabel, оставайтесь в цикле и продолжайте добавлять unitLabel и unitID), но есть ли более эффективный способ ?:
local.data.unitLabels = [];
for(local.row in local.__unitLabels){
local.unit = {};
local.unit.groupLabel = local.row.groupLabel;
local.unit.unitLabel = local.row.unitLabel;
local.unit.unitID = local.row.unitID;
// loop over the array so that we can identify which one needs to be preselected
for(local.dataValue in local.data.unitDetails){
if (local.unit.unitID eq local.dataValue.unitID) {
local.unit.selected = 'selected';
} else {
local.unit.selected = '';
}
}
arrayAppend(local.data.unitLabels, local.unit);
}
Данные JSON выглядят так, но у меня есть доступ к запросу, поэтому при необходимости я могу его переформатировать:
{
"data": {
"selectDataOptions": [{
"groupLabel": "COMPLETION",
"selected": "",
"unitID": 1,
"unitLabel": "Completion"
}, {
"groupLabel": "DISTANCE",
"selected": "",
"unitID": 2,
"unitLabel": "Meters"
}, {
"groupLabel": "DISTANCE",
"selected": "",
"unitID": 3,
"unitLabel": "Miles"
}, {
"groupLabel": "DISTANCE",
"selected": "",
"unitID": 4,
"unitLabel": "Yards"
}, {
"groupLabel": "TIME",
"selected": "",
"unitID": 5,
"unitLabel": "Hours"
}, {
"groupLabel": "TIME",
"selected": "",
"unitID": 5,
"unitLabel": "minutes"
}, {
"groupLabel": "TIME",
"selected": "",
"unitID": 5,
"unitLabel": "Seconds"
}]
}
}
В нынешнем виде мое поле выбора выглядит примерно так:
<select>
<optgroup>COMPLETION</optgroup>
<option>Complettion</option>
<optgroup>DISTANCE</OPTGROUP>
<option>Meters</option>
<optgroup>DISTANCE</optgroup>
<option>Miles</option>
<optgtroup>DISTANCE</optgroup>
<option>Yards</option>
<optgtroup>TIME</optgroup>
<option>Hours</option>
<optgtroup>TIME</optgroup>
<option>Minutes</option>
</select>
Обратите внимание, что повторяются optgroup Distance и TIME. Желаемый результат будет выглядеть так:
<select>
<optgroup>COMPLETION</optgroup>
<option>Complettion</option>
<optgroup>DISTANCE</OPTGROUP>
<option>Meters</option>
<option>Miles</option>
<option>Yards</option>
<optgroup>TIME</optgroup>
<option>Hours</option>
<option>Mintues</option>
</select>
Комментарий / вопрос о сложности правильный. Чтобы ответить на другие вопросы, данные будут заполнять плагин jQuery, Select2, так что параметры будут предварительно выбраны для пользователя. UnitID войдет в <option value=unitID>...</option>, но я оставил это, чтобы код был более лаконичным. Надеюсь, это не запутало меня больше.
Я только что вспомнил о проблеме определения объема при использовании FOR LOOPS с ColdFusion, поэтому мне, вероятно, придется заменить ее на INDEX LOOP.
Другими словами, проблема заключается в том, как создать строку JSON, которую может понять Select2? Я собирался предложить вложенный массив дочерних элементов, как описано в разделе «Сгруппированные данные» select2.org/data-sources/formats
Какую версию CF вы используете? IIRC, CF11 + поддерживают "группу" cfloop, что значительно упростит задачу ...
Предполагая, что данные сначала отсортированы по groupLabel, вот пример (игнорируйте различия меток) trycf.com/gist/9b0de6c843fbe3549128b1691fbafc27/…
Прошу прощения за задержку с возвращением, вышел на обед. Элемент, содержащий поле выбора, загружается после рендеринга DOM, поэтому Select2 должен применяться постфактум. Все, что мне нужно сделать, это создать поле выбора и применить плагин select2. Технически говоря, я использую Lucee 5.x, и он тоже поддерживает cfloop с группировкой.
Рассматривая суть ...
Позвольте нам продолжить обсуждение в чате.
созданная вами суть очень помогла. Все, что мне нужно сделать сейчас, это изменить мой JS, и я золотой. Команда cfloop / group была идеальным решением.
Если вы переместите свой GIST к ответу, я отмечу его как правильный. Деталь, которую я переработал, была data = []; cfloop(query = "qDemo", group = "groupLabel") { children = []; cfloop() { arrayAppend(children, {"id": qDemo.unitID, "text": qDemo.unitLabel}); } group = {"text" : qDemo.GroupLabel, "children" : children }; arrayAppend(data, group); }.
Отлично, рад, что помог!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Проблема в том, как создать строку JSON, которую может понять Select2? Я бы предложил создать вложенный массив дочерних элементов для каждого GroupLabel, как описано в документации в разделе Сгруппированные данные.
CF11 + и Lucee 4.5+ поддерживают cfloop "группа", что значительно упростит задачу. Просто выполните цикл по запросу и сгруппируйте его по "groupLabel". (NB: не забудьте изменить SQL-запрос и ORDER BY g.groupLabel, чтобы группировка работала должным образом.)
Код:
data= [];
cfloop(query = "qDemo", group = "groupLabel") {
children = [];
cfloop() {
arrayAppend(children, {"id": qDemo.unitID, "text": qDemo.unitLabel});
}
arrayAppend(data, {"text" : qDemo.GroupLabel, "children" : children });
}
writeDump(serializeJSON(data));
Результат:
[
{
"text": "COMPLETION",
"children": [
{
"text": "Completion",
"id": 1
}
]
},
{
"text": "DISTANCE",
"children": [
{
"text": "Meters",
"id": 2
},
{
"text": "Miles",
"id": 3
},
{
"text": "Yards",
"id": 4
}
]
},
{
"text": "TIME",
"children": [
{
"text": "Hours",
"id": 5
},
{
"text": "minutes",
"id": 5
},
{
"text": "Seconds",
"id": 5
}
]
}
]
Таким образом, трудность заключается в том, как лучше всего создать JSON, представляющий параметры списка, ИЛИ как использовать, который JSON во внешнем интерфейсе заполняет списки? Кроме того, я не уверен, что слежу за тем, как вы определяете, какие параметры следует выбрать заранее. Откуда взялся
local.dataValue.unitID? Я вижу это только один раз в коде ..