EN
sermonis
sermonis
13 июля 2017

Добрый день!

Каскадные select'ы встречаются довольно часто в разных формах. Законченного решения мне найти не удалось, ни на форуме ни в документации. Помогите, пожалуйста разобраться на конкретном примере. Как реализовать каскадные блоки select в технологии js по следующему сценарию:

  1. Допустим, мы имеем 3 select-блока с модификатором disabled (до инициализации), например: country, city, street.

  2. После автоматической (domReady) инициализации, первый select-блок (country) выполняет обращение к API, получает данные в json-формате, заполняется пунктами, на основании полученного массива данных и в случае успеха, с первого блока снимается модификатор disabled.

  3. Выбираем пункт country, получаем значение выбранного пункта, формируем запрос к API, получаем ответ, заполняем пункты второго блока (city), снимаем модификатор disabled со второго блока.

  4. Выбираем пункт city, получаем значение выбранного пункта, формируем запрос к API, получаем ответ, заполняем пункты третьего блока (street), снимаем модификатор disabled со третьего блока.

  5. При изменении значения, для нижестоящих по иерархии (country - city - street) блоков, процедура повторяется.

Заранее спасибо!

tadatuta
#tadatuta
16 июля 2017

Решение очень простое — на каждом шаге необходимый select следует создавать заново с помощью шаблонов на клиенте (либо присылать готовую разметку с сервера) и заменять им старый.

sermonis
#sermonis
18 июля 2017

Подскажите пожалуйста как быть с подпиской на событие onchange при замене select новым? Как возобновить подписку на событие?

tadatuta
#tadatuta
18 июля 2017

Подписываться с помощью делегированных событий в секции onInit() родительского блока.

sermonis
#sermonis
18 июля 2017

Спасибо, @tadatuta! Работает. Подписался на все селекты из родительского блока. А в статическом методе _onSelectChange сделал диспетчеризацию:

[...]

    _onSelectChange: function(e) 
    {
        if(e.bemTarget.getName() == 'brand_id')
        {
            this._setModels(e.bemTarget.getVal());
        }
        elseif(e.bemTarget.getName() == 'model_id')
        {
            this._setGenerations(e.bemTarget.getVal());
        }
    },

[...]

    onInit: function()
    {
        this._events(Select).on('change', this.prototype._onSelectChange);
        this.__base.apply(this, arguments);
    },

[...]

Правильно?

tadatuta
#tadatuta
18 июля 2017

Такой вариант в целом вполне рабочий.

Еще можно можно избавиться от if, если завернуть каждый селект в отдельный элемент родительского блока с собственной JS-реализацией, а наружу эмитить собственное событие.
Кода, конечно, станет больше, но он получится более модульный — если какой-то из селектов в последствии перестанет быть нужен, достаточно будет удалить его отдельный файл. Либо если вместо селекта станет использоваться какой-то другой контрол, в коде самого блока не потребуется никаких изменений.

sermonis
#sermonis
18 июля 2017

Спасибо, @tadatuta! Так и сделаю.

sermonis
#sermonis
19 июля 2017

Обернул необходимые селекты в соответствующие элементы родительского блока. В элементах сделал emit события onchange. Подскажите пожалуйста, как правильно обратиться к дочернему элементу из секции onInit() родительского блока для перехвата события?

this._events(this._elem('elemName')).on('change', this.prototype._onControlChange); не срабатывает.

tadatuta
#tadatuta
19 июля 2017

this._events('elemName').on('change', this.prototype._onControlChange);