Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Зависимые списки (select) на основе данных JSON (https://javascript.ru/forum/events/67555-zavisimye-spiski-select-na-osnove-dannykh-json.html)

mcmega 24.02.2017 00:01

Зависимые списки (select) на основе данных JSON
 
Всем привет! Очень нужна помощь. Принимаю от устройства пакет JSON такого формата:
[
    {
        "{{e1}}":[{"{{c1}}":"1", ... ,"{{cN}}":"5"}], 
        ...
        "{{eN}}":[{"{{c1}}":"1", ... ,"{{cN}}":"5"}]
    }
]


В объекте находятся элементы {{e}}, каждый со своим массивом. Реализованы зависимые элементы select.
В первом select - все названия ключей от {{e1}} до {{eN}}
Во втором select - все названия ключей от {{c1}} до {{cN}} со значением value соответствующего {{c}} (в зависимости от выбранного {{e}})

Ниже по форуму организована реализация.

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

рони 24.02.2017 00:23

mcmega,
зачем два раза получать одно и тоже?
в чём проблема создать селектор?

mcmega 24.02.2017 07:54

Цитата:

Сообщение от рони (Сообщение 445210)
mcmega,
зачем два раза получать одно и тоже?
в чём проблема создать селектор?

1. Нужно получать одно и тоже, потому что таких селекторов должно быть несколько на странице и их количество разное, каждый блок селекторов под своим ID
2. Проблема не в создании select, а в том, как добавлять элементы option в select в соответствии с данными из json динамически в зависимости от выбранного Event-а

рони 24.02.2017 09:07

mcmega,
1. если функции на 99% совпадают, значит нужна одна с дополнительным параметром, а может и его ненадо, но дело ваше, сколько функций.
2. есть обьект с данными - есть ключ первого селектора -- выбрали по ключу данные -- создали второй селектор

mcmega 24.02.2017 09:24

Цитата:

Сообщение от рони (Сообщение 445217)
mcmega,
1. если функции на 99% совпадают, значит нужна одна с дополнительным параметром, а может и его ненадо, но дело ваше, сколько функций.
2. есть обьект с данными - есть ключ первого селектора -- выбрали по ключу данные -- создали второй селектор

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

рони 24.02.2017 10:15

mcmega,
а так нельзя сделать?
function loadAPI(cnt,num){var apiData=JSON.parse(xhttp.responseText)[num];}

mcmega 24.02.2017 10:55

Цитата:

Сообщение от рони (Сообщение 445223)
mcmega,
а так нельзя сделать?
function loadAPI(cnt,num){var apiData=JSON.parse(xhttp.responseText)[num];}

Спасибо, работать по обьектно с данными json получилось.
А что дальше делать, как создать селект с именами ключей и добавить 2-ой зависимый селект?

рони 24.02.2017 11:25

зависимые селекты из json
 
mcmega,

медитируйте ...
<!DOCTYPE html>

<html>
<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style type="text/css">
  </style>


</head>

<body>
<div class="demo"></div>
<div class="show"></div>
<script>

var apiData = [{"В" : [{ "кричалки" : 5, "дразнилки" : 8 }], "голове" : [{}], "моей" : [{}], "опилки" : [{}]},
{"Сочиняю" : [{ "Шумелки" : 15, "пыхтелки" : 18, "сопелки" : 34}], "я" : [{}], "неплохо" : [{}], "иногда" : [{}]}
];

function set_select(select, data) {
    select.options.length = 0;
    Object.keys(data).forEach(function(key, k) {
        var value = typeof data[key] == "object" ? key : data[key];
        select.options[k] = new Option(key, value)
    })
}

function createS(selector, obj) {
    selector = document.querySelector(selector);
    var sel = document.createElement("select");
    var selTwo = sel.cloneNode();
    set_select(sel, obj);
    selector.appendChild(sel);
    selector.appendChild(selTwo);
    function test()
    {
      alert(this.value)
    }
    function change_select() {
        set_select(selTwo, obj[this.value][0]);
        test.bind(selTwo)()
    }

    sel.addEventListener("change", change_select);
    selTwo.addEventListener("change", test);
    change_select.bind(sel)()
};
createS(".demo", apiData[0])
createS(".show", apiData[1])


  </script>
</body>
</html>

mcmega 25.02.2017 14:35

Круто, все заработало, спасибо огромное!
Скажите, а как сделать чтоб при повторном вызове createAPISelect не создавался новый селектор, а менялся текущий?

рони 25.02.2017 15:07

mcmega,
<!doctype html>
<html>
<head>
  <title>Test</title>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
  <input value="Events" class="btn w45" onclick="createAPISelect('#eve', api[0]);" type="button">
  <input value="Actions" class="btn w45" onclick="createAPISelect('#act', api[1]);" type="button">
  <div id="eve"></div>
  <div id="act"></div>

</body>
  <script type="text/javascript">
var api =
[
  { "{{e1}}":[{"{{c1}}":"1","{{c2}}":"2","{{c3}}":"3"}],"{{e2}}":[{"{{c1}}":"1","{{c2}}":"2","{{c3}}":"3"}] },
  { "{{a1}}":[{"{{o1}}":"1","{{o2}}":"2","{{o3}}":"3"}],"{{a2}}":[{"{{o1}}":"1","{{o2}}":"2","{{o3}}":"3"}] }
];
// Загрузка API устройства
function setSelect(sel,obj){
  sel.options.length=0;
  Object.keys(obj).forEach(function(key,k){
    var value=typeof obj[key]=='object' ? key : obj[key];
    sel.options[k]=new Option(key,value);
  })
}
function createAPISelect(id,obj){
  var parEl=document.querySelector(id);
  var select = parEl.querySelectorAll('select')
  var sel = select.length ? select[0] : document.createElement('select');
  var selTwo = select.length == 2 ? select[1] : sel.cloneNode();
  setSelect(sel,obj);
  parEl.appendChild(sel);
  parEl.appendChild(selTwo);
  function changeSelect(){setSelect(selTwo,obj[this.value][0]);}
  sel.addEventListener('change',changeSelect);
  changeSelect.bind(sel)();
  //load();
}
  </script>
</html>

mcmega 25.02.2017 17:19

Гляньте пожалуйста почему не работают селекторы если подключаю переводчик полей {{}}, возможно не запоминается выбранный элемент в списках. Что не так с переводчиком?

<!doctype html>
<html>
<head>
  <title>Test</title>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
  <input value="Events" class="btn w45" onclick="createAPISelect('#eve', api[0]);" type="button">
  <div id="eve"></div>
  <script type="text/javascript">
var api = [{  "{{e1}}":[{"{{c1}}":"1","{{c2}}":"2"}], "{{e2}}":[{"{{c3}}":"1","{{c4}}":"2","{{c5}}":"3"}]  }];
function setSelect(sel,obj){
  sel.options.length=0;
  Object.keys(obj).forEach(function(key,k){
    var value=typeof obj[key]=='object' ? key : obj[key];
    sel.options[k]=new Option(key,value);
  })
}
function createAPISelect(id,obj){
  var parEl=document.querySelector(id);
  var select = parEl.querySelectorAll('select')
  var sel = select.length ? select[0] : document.createElement('select');
  sel.className='select w45';
  var selTwo = select.length == 2 ? select[1] : sel.cloneNode();
  setSelect(sel,obj);
  parEl.appendChild(sel);
  parEl.appendChild(selTwo);
  function changeSelect(){setSelect(selTwo,obj[this.value][0]);}
  sel.addEventListener('change',changeSelect);
  changeSelect.bind(sel)();
  LangTranslation(dicTrans);
}
// Переводчик
var dicTrans = {"e1":"it1","c1":"it1.1","c2":"it1.2","e2":"it2","c3":"it2.1","c4":"it2.2","c5":"it2.3"};
function LangTranslation(dicTrans){
  var data=document.getElementsByTagName('body')[0].innerHTML;
  var new_string;
  for(var key in dicTrans){new_string=data.replace(new RegExp('{{'+key+'}}','g'), dicTrans[key]); data=new_string;}
  document.getElementsByTagName('body')[0].innerHTML=data;
}
  </script>
</body>
</html>

рони 25.02.2017 17:45

mcmega,
потому что вы стираите страницу
Цитата:

Сообщение от mcmega
('body')[0].innerHTML=data;

а значит и все обработчики событий удаляются

рони 25.02.2017 18:08

mcmega,
<!doctype html>
<html>
<head>
  <title>Test</title>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
  <input value="Events" class="btn w45" onclick="createAPISelect('#eve', api[0]);" type="button">
  <div id="eve"></div>
  <script type="text/javascript">
var api = [{  "{{e1}}":[{"{{c1}}":"1","{{c2}}":"2"}], "{{e2}}":[{"{{c3}}":"1","{{c4}}":"2","{{c5}}":"3"}]  }];
function setSelect(sel,obj){
  sel.options.length=0;
  Object.keys(obj).forEach(function(key,k){
    var value=typeof obj[key]=='object' ? key : obj[key];
    // Переводчик текста option
    var dicTrans = {"e1":"it1","c1":"it1.1","c2":"it1.2","e2":"it2","c3":"it2.1","c4":"it2.2","c5":"it2.3"};
    var trKey = key.replace(/[\{\}]/g,"");
    var text  = dicTrans[trKey]||key ;
    sel.options[k]=new Option(text,value);
  })
}
function createAPISelect(id,obj){
  var parEl=document.querySelector(id);
  var select = parEl.querySelectorAll('select')
  var sel = select.length ? select[0] : document.createElement('select');
  sel.className='select w45';
  var selTwo = select.length == 2 ? select[1] : sel.cloneNode();
  setSelect(sel,obj);
  parEl.appendChild(sel);
  parEl.appendChild(selTwo);
  function changeSelect(){setSelect(selTwo,obj[this.value][0]);}
  sel.addEventListener('change',changeSelect);
  changeSelect.bind(sel)();
}
</script>
</body>
</html>

mcmega 25.02.2017 18:23

От я балда, совсем забыл про это, спасибо!
Скажите, а никак нельзя модернизировать функцию перевода чтоб она не затрагивала обработчики событий?
Потому что этой функцией переводится вся страница, а словарь dicTrans подгружается из сети. Я его вынес отдельно только для примера.

рони 25.02.2017 18:53

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

mcmega 25.02.2017 19:12

рони,

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

Сейчас для построения зависимых select-ов происходит такая последовательность:
0. Загружается весь html
1. Запрашивается файл configs (здесь мы узнаем язык)
2. Запрашивается соответствующий словарь
3. Запрашивается файл api.json
4. Формируется форма из селектов и т.д. (т.е. весь стартовый код html)
5. Производится перевод страницы

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


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