Отображение зависимых данных, на примере использования двух ниспадающих списков, посредством knockout

в 15:41, , рубрики: javascript, Knockout.js, метки: ,

В этом посте я хотел бы показать основные возможности knockout по работе с данными в раскрывающихся списках (тег <select>). Как оказалось тут есть свои мелочи, на которые стоит обратить внимание при использовании, такого мощного инструмента как knockout.

Добро пожаловать под кат!

Описание

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

Реализация (приводится упрощенная реализация)

В ходе реализции были созданы следующие модели классов:

Описание моделей на javascript

Модель типа организации:

function OrgType(idv, namev, subTypesv){
        var id = ko.observable(idv),
            name = ko.observable(namev),
            subTypes = ko.observableArray(subTypesv);
        return {
            id : id,
            name : name,
            subTypes : subTypes
        };
    }
Модель суб типа организации:

function OrgSubType(idv, namev){
        var id = ko.observable(idv),
            name = ko.observable(namev);
        return {
            id : id,
            name : name            
        };         
    }
И основная (главная) модель для отображения на форме:
function OrgTypesModel(){
        var orgTypes = ko.observableArray([
            new OrgType(1,'tp1',
                        [new OrgSubType(1,'subT1'), 
                         new OrgSubType(2,'subT2'), 
                         new OrgSubType(3,'subT3')]),
            
            new OrgType(2,'tp2',
                        [new OrgSubType(4,'subT4'), 
                         new OrgSubType(5,'subT5'), 
                         new OrgSubType(6,'subT6'),
                         new OrgSubType(7,'subT7')])]),
            
            selectedOrgTypeId = ko.observable(1),
            selectedOrgType = ko.computed(function(){
               var otList = orgTypes(),
                   selId = selectedOrgTypeId();
                for(var i =0; i<otList.length; i++){
                    if(otList[i].id()==selId)
                        return otList[i];
                }
                return null;                   
            }),
            
            selectedOrgSubTypeId = ko.observable(1),
            selectedOrgSubType = function(){
               var otList = selectedOrgType().subTypes(),
                   selId = selectedOrgSubTypeId();
                for(var i =0; i<otList.length; i++){
                    if(otList[i].id()==selId)
                        return otList[i];
                }
                return null;                   
            };                           

        return {
            orgTypes  : orgTypes,
            selectedOrgTypeId : selectedOrgTypeId,
            selectedOrgType  : selectedOrgType,
            selectedOrgSubTypeId  : selectedOrgSubTypeId,
            selectedOrgSubType : selectedOrgSubType
        };            
    }
  • Таким образом главная модель предоставляет список типов организаций посредством свойства orgTypes
  • В свойстве selectedOrgTypeId хранится значение идентификатора выбранного типа организации
  • Из свойства selectedOrgType получаем объект типа организации *
  • Посредством selectedOrgSubTypeId получаем идентификатор выбранного суб типа организации
  • Посредством свойства selectedOrgSubType — получает объект суб типа организации

Html код

<div>
<select data-bind="options: orgTypes, optionsText: 'name', optionsValue: 'id', value: selectedOrgTypeId">
</select>
<span data-bind="text: selectedOrgType().name"></span>
</div>
<div>
<select data-bind="options: selectedOrgType().subTypes, optionsText: 'name', optionsValue: 'id', value: selectedSubOrgTypeId"></select>
<span data-bind="text: selectedSubOrgType().name"></span>
</div>

Заметки

В ходе реализации я наткнулся на неумение knockout выделять в раскрывающемся списке выбранное значение и как оказалось и об этом писали на StackOwerflow. Решение данной проблемы заключается в использовании optionsText: 'name', optionsValue: 'id' конструкции маппинга в совокупности с value: selectedOrgTypeId. После установки параметров в html коде выбранное значение правильно устанавливается в ниспадающем списке. Но данное решение, накладывает свое ограничение — при этом не возможно просто получить доступ к другим значениям выбранного значения, кроме как к id.
И для решения проблемы, используется поиск значения по id в списке и последующий возврат его. Реализацию данного подхода можно увидеть в теле свойства selectedOrgType или selectedOrgSubType.

Но на этом не закончились интересные моменты. При попытке использовать ko.computed для свойства selectedOrgSubType, реализация не работала, скорее всего по причине особенности работы самого метода. Только после того, как я убрал ko.computed, задач была решена.

Ссылки

Реализацию можно пощупать на jsFiddle

Спасибо за внимание! Надеюсь данная статья будет интересна :)

Автор: CyberLight

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js