Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 07.07.2017, 17:51
Новичок на форуме
Отправить личное сообщение для Fierfoxik Посмотреть профиль Найти все сообщения от Fierfoxik
 
Регистрация: 27.04.2016
Сообщений: 8

Ревью автокомплита Combo box
Доброго времени, заранее извиняюсь за многословность.

Не так давно попалось тестовое задание реализовать автокомплит списка городов.
Из функционала:
  1. При вводе первого символа список фильтруется. Первый пункт в списке подсвечивается. Оптимальное количество строк в списке — 5. Если после фильтрации список может быть очень большим, это число можно увеличивать до 20.

  2. Если обработка запроса для построения списка занимает дольше 0,5 секунды, показываем лоадер минимум 1 секунду. Если список уже открыт, и при получении ответа возникла задержка — показываем лоадер, список до обновления остается в прежнем состоянии.

  3. Если происходит ошибка сервера, показываем сообщение об ошибке и кнопку обновить.

  4. Если для введенного нет совпадений, показываем соответствующий тест.

  5. Потеря фокуса без выбора пункта из списка
    Если ничего не найдено, показываем ошибку

  6. Если список не успел загрузиться, показываем ошибку

  7. Если введенное значение посимвольно совпадает со значением из справочника, при потере фокуса выбираем его

  8. При получении фокуса введенное значение выделяется

Так же некоторые вещи не совсем так или вообще не сделал и мне теперь стало интересно как можно было бы это реализовать.

Во 2 пункте прелоадер показывается только до полной загрузки данных и убирается после загрузки данных.
В 7 пункте я не могу понять как сравнить сразу данные из массива и полное слово.
И интересно как бы сделать активный класс при нажатии на результат т.к очищать класс до добавления класса мне не удалось.


Хотелось бы услышать советы более опытных программистов по поводу улучшения кода.


codepen


let homeworkContainer = document.querySelector('#homework-container'),
    filterBlock = document.getElementById('filter-block'),
    filterInput = homeworkContainer.querySelector('#filter-input'),
    filterResult = homeworkContainer.querySelector('#filter-result'),
    filterList = homeworkContainer.querySelector('.filter-list'),
    info = homeworkContainer.querySelector('.info-block'),
    reoladBtn = document.createElement('div'),
    filtrFocusOut;

function createCORSRequest(method, url) {
    let xhr = new XMLHttpRequest();

    if ('withCredentials' in xhr) {
        // XHR for Chrome/Firefox/Opera/Safari.
        xhr.open(method, url, true);
    } else if (typeof XDomainRequest != 'undefined') {
        // XDomainRequest for IE.
        xhr = new XDomainRequest();
        xhr.open(method, url);
    } else {
        // CORS not supported.
        xhr = null;
    }
    
    return xhr;
}

function loadAndSortTowns() {
    return new Promise(function(resolve) {
        let url = './data/kladr.json',
            preloader = document.createElement('div'),
            xhr = createCORSRequest('GET', url);

        preloader.className = 'input__preloader';

        if (!xhr) {
            alert('CORS not supported');
            
            return;
        }
        xhr.responseType = 'json';
        filtrFocusOut = true;
        filterBlock.appendChild(preloader);

        xhr.onload = function() {
            let resp = xhr.response;

            preloader.remove();
            filtrFocusOut = false;

            if (xhr.status === 200 && xhr.readyState === 4) {
                resp.sort(function(a, b) {
                    if (a.name > b.name) {
                        return 1
                    }

                    return -1
                });
                resolve(resp);
            } else {
                reoladBtn.innerHTML = 'Обновить';
                reoladBtn.className += 'reolad-btn';
                filterList.appendChild(reoladBtn);
                filterResult.innerHTML = 'Что то пошло не так. Проверьте соединение с интернетом и попробуйте еще раз'

            }
        };

        xhr.send();

    })
}

function checkFilterStatus (array, count) {
    if (array.length === 0) {
        info.innerHTML = 'Не чего не найдено';
        filtrFocusOut = true;
    } else {
        filtrFocusOut = false;
        filterInput.parentNode.classList.remove('filter-erore');
        if (count > 1) {
            info.innerHTML = 'Показано ' + count + ' из ' + array.length + ' найденных городов. Уточните запрос, чтобы увидеть остальные'
        } else {
            info.innerHTML = ''
        }
    }
}

function isMatching(full, chunk) {
    full = full.toLowerCase();
    chunk = chunk.toLowerCase();
    if (full.substr(0, chunk.length) === chunk) {
        return true;
    } 
    
    return false;
    
}

filterInput.oninput = function(e) {
    e.target.parentNode.classList.remove('filter-erore');

    loadAndSortTowns().then(function (data) {
        let value = e.target.value.trim(),
            htmlText = '',
            checkArray = [],
            count = 0;

        if (value.length > 0) {
            filterList.classList.add('is--show');
            for (let i= 0; i<data.length; i++) {
                if (isMatching(data[i].City, value)) {
                    checkArray.push(data[i].City);
                    if (checkArray.length <= 5) {
                        count++;
                        htmlText += '<div id=' + data[i].Id + ' ' + 'class="result__item">' + data[i].City + '</div>';
                    }
                } else {
                    checkFilterStatus(checkArray, count, htmlText)
                }
            }

        } else {
            filterList.classList.remove('is--show');
            info.innerHTML = '';
        }

        filterResult.innerHTML = htmlText;

    });
};

filterList.onclick = function (e) {
    if ( e.target.className.indexOf('result__item') === 0) {
        filterList.classList.remove('is--show');
        filterInput.value = e.target.innerHTML;
    }
};

filterInput.onchange = function (e) {

    if (filtrFocusOut) {
        e.target.parentNode.classList.add('filter-erore');
        info.innerHTML = 'Выберите значение из списка';
    }
};

filterInput.onfocus = function(e) {
    e.target.setSelectionRange(0, this.value.length);
};

reoladBtn.onclick = function () {
    loadAndSortTowns();
};
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Передача параметра в proxy из combo adamenko.artem ExtJS 1 08.07.2014 17:34
Изменение Ext.data.Store для combo yo-y0 ExtJS 3 20.08.2012 14:51
Правильная отрисовка combo в grid Eugent ExtJS 7 28.04.2012 13:22
animate, всплывающий div box сделать по центру zero_mod jQuery 1 27.10.2010 00:23