Связанные выпадающие списки в Grails

#javascript #grails #drop-down-menu

#javascript #grails #выпадающее меню

Вопрос:

Мой домен выглядит примерно так:

В продуктовой строке есть множество тем и подтем.

В представлении Subtemic create.gsp я хочу иметь два выпадающих списка — первый для выбора продуктовой линейки, затем во втором я хочу показать темы, которые принадлежат к ранее выбранной продуктовой линейке. Как это реализовать?

Ответ №1:

Объединить два выпадающих списка вместе не так уж сложно, но связать три или более в цепочку может быть сложно в первый раз. Ниже я объединяю три выпадающих списка вместе, но вы должны быть в состоянии извлечь из этого примера, как объединить любое количество выпадающих списков вместе.

В моем Load классе, когда я создаю новый экземпляр, мне нужно знать, кто был поставщиком груза, какой источник груза использовался и что это был за груз. Например, представьте, что у меня есть поставщик грузовых перевозок с именем ACME Rock. Тогда представьте, что у ACME Rock есть два местоположения, из которых они доставляют грузы, 123 Somewhere Road и 456 Nowhere Road. Эти местоположения будут представлять источники груза. Наконец, представьте, что каждый источник грузов предлагает разные грузы. Мы представим, что 123 Где-то дорога производит только камень, а 456 Нигде дорога производит только грязь. Учитывая все сказанное, вот как выглядят выпадающие списки в представлении создания (create.gsp) для моего Load класса.

         <tr class="prop">
            <td valign="top" class="name">
                <label for=cargoProvider"><g:message code="load.cargoProvider.label" default="Cargo Provider"/></label>
            </td>
            <td valign="top" class="value ${hasErrors(bean: loadInstance, field: 'cargoProvider', 'errors')}">
                <g:select from="${cargoProviders}" id="cargoProvider.id" name="cargoProvider.id" noSelection="['':'-Select-']" optionKey="id" optionValue="${{it.businessName?.toString()   ': '   it?.toString()}}" value="${loadInstance?.cargoProvider?.id}"/>
            </td>
        </tr>

        <tr class="prop">
            <td valign="top" class="name">
                <label for="cargoSource"><g:message code="load.cargoSource.label" default="Cargo Source"/></label>
            </td>
            <td id="cargoSourceCell" valign="top" class=" value ${hasErrors(bean: loadInstance, field: 'cargoSource', 'errors')}">
                <g:select from="${loadInstance?.cargoSource}" id="cargoSource.id" name="cargoSource.id" optionKey="id" value="${loadInstance?.cargoSource?.id}"/>
            </td>
        </tr>

        <tr class="prop">
            <td valign="top" class="name">
                <label for="cargo"><g:message code="load.cargo.label" default="Cargo"/></label>
            </td>
            <td id="cargoCell" valign="top" class="value ${hasErrors(bean: loadInstance, field: 'cargo', 'errors')}">
                <g:select from="${loadInstance?.cargo}" id="cargo.id" name="cargo.id" optionKey="id" value="${loadInstance?.cargo?.id}"/>
            </td>
        </tr>
  

Мы начинаем объединять эти выпадающие списки в цепочку с некоторым JavaScript, расположенным на той же странице (create.gsp). Не забудьте поместить свой JavaScript прямо перед </body> тегом, который закрывает элемент body. Пожалуйста, также обратите внимание, что я использую jQuery, а не Prototype.

 <g:javascript>
    $(document).ready(function() {
        $("#cargoProvider\.id").change(function() {
            var cargoSourceValue = $("#cargoSource\.id").val();
            $.ajax({
                url: "/truckingmanagement/load/getCargoSources",
                data: "id="   this.value,
                dataType: 'html',
                cache: false,
                success: function(result) {
                    $("#cargoSourceCell").html(result);
                    $("#cargoSource\.id").val(cargoSourceValue);
                    $("#cargoSource\.id").trigger('change');
                }
            });
        });
    });
</g:javascript>

<g:javascript>
    function updateCargoes() {
        var data = ($("#cargoSource\.id").val() == null) ? "" : $("#cargoSource\.id").val();
        var cargoValue = $("#cargo\.id").val();
        $.ajax({
            url: "/truckingmanagement/load/getCargoes",
            data: "id="   data,
            dataType: 'html',
            cache: false,
            success: function(result) {
                $("#cargoCell").html(result);
                $("#cargo\.id").val(cargoValue);
            }
        });
    }
</g:javascript>
  

На первый взгляд может показаться, что updateCargoes функция ничего не делает, но на самом деле это так. Когда в первом раскрывающемся списке делается выбор, второе раскрывающееся окно заполняется HTML, сгенерированным инструкцией Grails render в моем контроллере загрузки. Это, по сути, заменяет исходное выпадающее окно на новое, таким образом, любые атрибуты, которые я изначально записал в выпадающее окно, будут потеряны, если они также не включены в render инструкцию. Вот почему вы видите, что ниже вы видите onchange: 'updateCargoes(); включенные в render инструкцию getCargoSources действия моего контроллера загрузки, а также другие атрибуты, которые мне нужны для правильного выполнения моего приложения. Атрибуты, которые вы включаете, будут различаться в зависимости от того, что именно вы хотите сделать в своем представлении, и те, которые я выбрал, довольно стандартны. Ввод атрибутов дважды вызывает раздражение, но это лучше, чем альтернатива загрузки всего набора данных в выпадающий список при загрузке страницы, действие, которое может быть очень неэффективным в зависимости от того, сколько у вас данных.

 def getCargoSources = {
    if(params.id == ""){
        render g.select(name: 'cargoSource.id', onchange: 'updateCargoes(); updateTotal()')
        return
    }

def getCargoes = {
    if(params.id == ""){
        render g.select(name: 'cargo.id', onchange: 'updateTotal()')
        return
    }
    def cargoSource = Address.get(params.id)
    def cargoes = Cargo.findAll("from Cargo as cargoes where cargoes.cargoSource=:cargoSource", [cargoSource: cargoSource])
    render g.select(from: cargoes,  name: 'cargo.id', noSelection: noSelection, onchange: 'updateTotal()', optionKey: 'id')
} 
  

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

Комментарии:

1. у меня не было TD для создания дампа html, который я просто хотел перезаписать или обновить из результата в моем текущем выпадающем списке?

2. @danielad Извините, но я не понимаю, о чем вы говорите.

Ответ №2:

Комментарии:

1. Пожалуйста, смотрите Действительно ли ответы, которые содержат ссылки в другом месте, действительно «хорошие ответы»?