Временная проблема при настройке выбранного элемента раскрывающегося списка в обработчике готовности документа - PullRequest
1 голос
/ 08 июля 2011

Предыстория: я работаю над своим первым приложением ASP.NET MVC 3 и хочу предоставить клиенту две похожие страницы - «Создать» и «Редактировать». На обеих страницах есть два селектора DropDownList, которые позволяют клиенту сначала выбрать тип конуса или блюда, а затем выбрать подтип на основе первого выбора (например, клиент выбирает «вафельный конус», а затем ему предоставляются подтипы, такие как «шоколадный соус», "обычный" и т. д.).

Я набираю событие 'change' в селекторе ConeDish, чтобы вызвать действие Controller для возврата связанных подтипов. Примерно так:

View

<td>@Html.DropDownListFor(model => model.TypeID, new SelectList(Model.ConeDishTypes, "TypeID", "Name"), "-- Select Cone or Dish --", new { @id = "conedishselector" })
</td>
<td>@Html.DropDownListFor(model => model.SubtypeID, Enumerable.Empty<SelectListItem>(), "-- How Big? --", new { @id = "subtypeselector" })
</td>

Мой обработчик готовности документа для страницы Создать выглядит следующим образом:

<script type="text/javascript">
    $(document).ready(function () {
        $('#conedishselector').change(function () {
            var selectedTypeID = $(this).val();
            if (selectedTypeID != null) {
                $.getJSON('@Url.Action("SubtypesForType")', { typeID: selectedTypeID }, function (subtypes) {
                    var subtypesSelect = $('#subtypeselector');
                    subtypesSelect.empty();
                    subtypesSelect.append($('<option/>', { value: 0, text: '-- How Big? --' }));
                    $.each(subtypes, function (index, subtype) {
                        subtypesSelect.append($('<option/>', {
                            value: subtype.SubtypeID,
                            text: subtype.Name
                        }));
                    });
                });
            }
        });
    });
</script>

Контроллер

И у меня есть действие контроллера, которое выглядит так:

public ActionResult SubtypesForType(int typeID)
{
    using (var db = new IceCreamEntities())
    {
        IEnumerable<Subtypes> subtypes = db.Subtypes.Where(m => m.TypeID == typeID).ToList();
        List<SubtypeIdentifierViewModel> subtypeVMs = new List<SubtypeIdentifierViewModel>();
        foreach (var subtype in subtypes)
        {
            subtypeVMs.Add(new SubtypeIdentifierViewModel(subtype.SubtypeID, subtype.Name, subtype.Size));
        }
        return Json(subtypeVMs, JsonRequestBehavior.AllowGet);
    }
}

По сути, это просто получение подтипов, для которых в действие передан соответствующий TypeID. Я не думаю, что структура модели представления уместна для обсуждения, поэтому она не используется для экономии места.

Теперь этот бит для Create , кажется, работает довольно хорошо. Могут быть способы улучшить его (что я был бы рад услышать), но это достигает моей цели.

Но для страницы Edit у меня возникли трудности с отображением ранее выбранного подтипа в пользовательском интерфейсе. Мой текущий код скрипта выглядит так:

<script type="text/javascript">
    $(document).ready(function () {
        $('#conedishselector').change(function () {
            var selectedTypeID = $(this).val();
            if (selectedTypeID != null) {
                $.getJSON('@Url.Action("SubtypesForType")', { typeID: selectedTypeID }, function (subtypes) {
                    var subtypesSelect = $('#subtypeselector');
                    subtypesSelect.empty();
                    subtypesSelect.append($('<option/>', { value: 0, text: '-- How Big? --' }));
                    $.each(subtypes, function (index, subtype) {
                        subtypesSelect.append($('<option/>', {
                            value: subtype.SubtypeID,
                            text: subtype.Name
                        }));
                    });
                });
            }
        });

        $('#conedishselector').trigger("change");

        var theVal = $("#hiddensubtypeid").val();
        $("#debug").val(theVal);
        if (theVal != null && theVal != "") {
            // alert here just to check
            alert("I got here.");
            $('#subtypeselector').val(theVal);
            // I also tried this, but that didn't work without the alert either - didn't think it would though 
            //            $("#subtypeselector option[value=" + val + "]").attr("selected", "selected");
        }
    });
</script>       

По существу, поле hiddensubtypeid на странице содержит ранее выбранный идентификатор для редактируемого здесь мороженого, и сценарий использует это значение для установки селектора, который был заполнен соответствующими подтипами, как это было сделано в Create скрипт страницы.

И здесь я, возможно, не буду делать это «в соответствии с рекомендациями» или даже хорошим способом (то есть, используя это скрытое поле или вызывая изменение через триггер внутри обработчика готовности документа), но я не был уверен, как это сделать. сделать это иначе.

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

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


Немного больше информации из отдела "Это чувствуется хаки":

Если я попытаюсь использовать setTimeout, чтобы отложить такие вещи:

$('#conedishselector').trigger("change");
$(function($) {
    setTimeout(function() {       
        var theVal = $("#hiddensubtypeid").val();
        $("#debug").val(theVal);
        if (theVal != null && theVal != "") {
            // alert here just to check
            alert("I got here.");
            $('#subtypeselector').val(theVal);
        }
    }, 200); // or 500, or 1000
});

Все будет работать, но я думаю, что это в лучшем случае решение проблемы с помощью клейкой ленты.


A Решение:

Так что я полагаю, что все это сводится к тому, что getJSON является асинхронным вызовом ( Reference ), и это ясно из документов, так как он имеет успешный обратный вызов , который получает выполняется в какой-то момент в будущем , если запрос завершится успешно. Так что это значит? Это означает, что перебор функции готовности документа, вызов $('#yourfavoriteselector').trigger("change");, а затем немедленный поворот и ожидание результатов getJSON является ошибочной логикой. Задержка ожидания, как я делал выше с помощью setTimeout, является хаком и приводит к неоптимальному «решению» проблемы. Он опирается (плохо, я мог бы добавить) на мысль, что обратный вызов успеха сработает после ожидания 500 мс или в любое другое указанное время.

Я перестроил функцию так:

<script type="text/javascript">
    $(document).ready(function () {
        $('#conedishselector').change(function () {
            var selectedTypeID = $(this).val();
            if (selectedTypeID != null) {
                $.getJSON('@Url.Action("SubtypesForType")', { typeID: selectedTypeID }, function (subtypes) {
                    var subtypesSelect = $('#subtypeselector');
                    subtypesSelect.empty();
                    subtypesSelect.append($('<option/>', { value: 0, text: '-- How Big? --' }));
                    $.each(subtypes, function (index, subtype) {
                        subtypesSelect.append($('<option/>', {
                            value: subtype.SubtypeID,
                            text: subtype.Name
                        }));
                    });
                    var theVal = $("#hiddensubtypeid").val();
                    if (theVal != null && theVal != "") {
                       $('#subtypeselector').val(theVal);
                    }
                });
            }
        });

        $('#conedishselector').trigger("change");
    });
</script>

и, как предположил Бэджер, сделал выбор как часть обратного вызова успеха, который обеспечил заполнение подтипов.

Преимущество такого способа также заключается в том, что пользователь может изменить выбор первого DropDownList на какое-то новое значение (скажем, хочет ли он посмотреть, какие другие конусы / блюда мы предлагаем) и вернуть его к исходному значению. снова. Когда это происходит, скрытое поле по-прежнему содержит исходный подтип, соответствующий исходному основному типу, и код обратного вызова соответственно сбрасывает подтип DropDownList. Таким образом, пользователя не раздражает необходимость заново выбирать размер блюда или тип вафельного рожка. Мне кажется, это лишь немного уважения к пользователю и приятный побочный эффект представленного решения.

Так что это «решение» и, возможно, не лучшее решение, но я хотел бы проиллюстрировать его для полноты.

1 Ответ

1 голос
/ 08 июля 2011

Я думаю, что ваша проблема действительно в выборе времени.Вы отправляете запрос данных и затем пытаетесь установить выбранный элемент, не ожидая ответа JSON.

Если нет особой причины, я бы реализовал функцию успеха getJSON иначе.

В случае успеха при загрузке подтипов вы можете проверить, является ли один из них вашим скрытым подтипом.Если это так, выберите его, если нет, то оставьте значение по умолчанию.

Если вы хотите, вы можете очистить hiddensubtypeid, когда он был «использован» функцией успеха, хотя это может иметь смысл с точки зрения вашего пользователя.опыт всегда переходить к выбранному в данный момент элементу, если пользователь выбирает соответствующий основной тип.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...