web-dev-qa-db-ja.com

JSP / Servletでカスケードドロップダウンリストを作成する

dd1dd2dd3という名前の3つのドロップダウンリストコントロールがあるとします。各ドロップダウンリストの値はデータベースから取得されます。 dd3の値はdd2の値に依存し、dd2の値はdd1の値に依存します。この問題のためにサーブレットをどのように呼び出すのですか?

39
deven

これを実現するには、基本的に3つの方法があります。

  1. 1番目のドロップダウンのonchangeイベント中にフォームをサーブレットに送信し(これにJavascriptを使用できます)、1番目のドロップダウンの選択されたアイテムをリクエストパラメーターとしてサーブレットに取得させ、2番目のドロップダウンの関連値をデータベースから取得させます_Map<String, String>_として、それらを要求スコープに保存します。最後に、JSP/JSTLに2番目のドロップダウンに値を表示させます。使用できます [〜#〜] jstl [〜#〜] (ドロップするだけで jstl-1.2.jar in _/WEB-INF/lib_) _c:forEach_ このタグ。 JSPページに関連付けられたServletdoGet()メソッドで最初のリストを事前に設定できます。

    _<select name="dd1" onchange="submit()">
        <c:forEach items="${dd1options}" var="option">
            <option value="${option.key}" ${param.dd1 == option.key ? 'selected' : ''}>${option.value}</option>
        </c:forEach>
    </select>
    <select name="dd2" onchange="submit()">
        <c:if test="${empty dd2options}">
            <option>Please select parent</option>
        </c:if>
        <c:forEach items="${dd2options}" var="option">
            <option value="${option.key}" ${param.dd2 == option.key ? 'selected' : ''}>${option.value}</option>
        </c:forEach>
    </select>
    <select name="dd3">
        <c:if test="${empty dd3options}">
            <option>Please select parent</option>
        </c:if>
        <c:forEach items="${dd3options}" var="option">
            <option value="${option.key}" ${param.dd3 == option.key ? 'selected' : ''}>${option.value}</option>
        </c:forEach>
    </select>
    _

    ただし、これはentireフォームを送信し、ユーザーエクスペリエンスに悪い「コンテンツのフラッシュ」を引き起こすという点に注意してください。また、リクエストパラメータに基づいて、同じフォームの他のフィールドを保持する必要があります。また、リクエストがドロップダウンの更新(子ドロップダウン値がnull)であるか、実際のフォームを送信するかをサーブレットで決定する必要があります。

  2. 2番目と3番目のドロップダウンのすべての可能な値をJavascriptオブジェクトとして出力し、Javascript関数を使用して、1番目のドロップダウンのonchangeイベント中に、1番目のドロップダウンの選択項目に基づいて2番目のドロップダウンを埋めます。ここでは、フォームの送信やサーバーサイクルは不要です。

    _<script>
        var dd2options = ${dd2optionsAsJSObject};
        var dd3options = ${dd3optionsAsJSObject};
        function dd1change(dd1) {
            // Fill dd2 options based on selected dd1 value.
            var selected = dd1.options[dd1.selectedIndex].value;
            ...
        }
        function dd2change(dd2) {
            // Fill dd3 options based on selected dd2 value.
            var selected = dd2.options[dd2.selectedIndex].value;
            ...
        }
    </script>
    
    <select name="dd1" onchange="dd1change(this)">
        <c:forEach items="${dd1options}" var="option">
            <option value="${option.key}" ${param.dd1 == option.key ? 'selected' : ''}>${option.value}</option>
        </c:forEach>
    </select>
    <select name="dd2" onchange="dd2change(this)">
        <option>Please select parent</option>
    </select>
    <select name="dd3">
        <option>Please select parent</option>
    </select>
    _

    ただし、多数のアイテムがある場合、これは不必要に長くなり、高価になる可能性があるという注意点があります。 JSオブジェクトに100 * 100 * 100 = 1,000,000個のアイテムが存在する可能性がある100個のアイテムごとに3つのステップがあるとします。 HTMLページの長さは1MBを超えます。

  3. JavascriptのXMLHttpRequestを使用して、最初のドロップダウンのonchangeイベント中にサーブレットへの非同期リクエストを起動し、サーブレットが最初のドロップダウンの選択されたアイテムをリクエストパラメータとして取得し、2番目のドロップダウンの関連する値をデータベース、XMLまたは [〜#〜] json [〜#〜] 文字列として返します。最後に、JavascriptにHTML DOMツリーを介して2番目のドロップダウンに値を表示させます(以前に提案したAjaxの方法)。これに最適な方法は、 jQuery を使用することです。

    _<%@ page pageEncoding="UTF-8" %>
    <%@ taglib uri="http://Java.Sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>SO question 2263996</title>
            <script src="http://code.jquery.com/jquery-latest.min.js"></script>
            <script>
                $(document).ready(function() {
                    $('#dd1').change(function() { fillOptions('dd2', this); });
                    $('#dd2').change(function() { fillOptions('dd3', this); });
                });
                function fillOptions(ddId, callingElement) {
                    var dd = $('#' + ddId);
                    $.getJSON('json/options?dd=' + ddId + '&val=' + $(callingElement).val(), function(opts) {
                        $('>option', dd).remove(); // Clean old options first.
                        if (opts) {
                            $.each(opts, function(key, value) {
                                dd.append($('<option/>').val(key).text(value));
                            });
                        } else {
                            dd.append($('<option/>').text("Please select parent"));
                        }
                    });
                }
            </script>
        </head>
        <body>
            <form>
                <select id="dd1" name="dd1">
                    <c:forEach items="${dd1}" var="option">
                        <option value="${option.key}" ${param.dd1 == option.key ? 'selected' : ''}>${option.value}</option>
                    </c:forEach>
                </select>
                <select id="dd2" name="dd2">
                    <option>Please select parent</option>
                </select>
                <select id="dd3" name="dd3">
                    <option>Please select parent</option>
                </select>
            </form>
        </body>
    </html>
    _

    ..where _/json/options_の後ろのServletは次のようになります:

    _protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String dd = request.getParameter("dd"); // ID of child DD to fill options for.
        String val = request.getParameter("val"); // Value of parent DD to find associated child DD options for.
        Map<String, String> options = optionDAO.find(dd, val);
        String json = new Gson().toJson(options);
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write(json);
    }
    _

    ここで、GsonGoogle Gson です。これにより、十分なJavaオブジェクトをJSONに、またはその逆に変換しやすくなります。参照: サーブレットの使用方法Ajax?

48
BalusC

あなたの質問から判断すると、実際にはWebフレームワークを使用しているのではなく、サーブレットを使用してhtmlをレンダリングしています。

私はニースであり、あなたは時代から約10年遅れていると言います:)、人々はこの種のことのためにJSP(およびストラットのようなWebフレームワーク)を使用します。しかし、それを言って、ここに行きます:

  1. フォームに非表示フィールドを作成し、入力するドロップダウンに応じて値を「1」、「2」または「3」に設定します。
  2. サーブレットで、この値(request.getParamter())をキャプチャし、「case」/ if/elseステートメントを使用して適切なドロップダウン値を返します。

繰り返しますが、Webフレームワークを使用するか、少なくとも古いjspを使用してこれを行います。

4
Ryan Fernandes

これには複数のサーブレットが必要になる場合があります。

サーブレット1:最初のドロップダウンリストの値をデータベースからロードします。 JSPページで、ドロップダウンリストを作成します。ユーザーが値を選択すると、サーブレット2に送信されます。

サーブレット2:最初のリストから値を取得し、2番目のリストの値に対してデータベース検索を実行します。 2番目のリストを作成します。ユーザーが2番目の値を選択したら、それをサーブレット3に送信します。

サーブレット3:2番目のドロップダウンで選択した値を取得し、データベース検索を実行して最後のドロップダウンの値を取得します。

AJAXを検討すると、ユーザーにリストのデータがシームレスに表示されるようになります。jQueryには、これを簡単に行うための非常に素晴らしいプラグインがあります。


     <form action="servlet2.do">
          <select name="dd1" onchange="Your JavaScript Here">
               <option>....
          </select>
     </form>

Onchangeイベントでフォームを送信するJavaScriptを記述できます。繰り返しますが、jQueryのような既存のライブラリを使用すると、10倍簡単になります。

4

それは素晴らしいシンプルなソリューションでした。私はJQueryコードがどれほど小さいかが好きで、GSON APIへのリンクを本当に感謝しています。すべての例がこれを簡単な実装にしました。

親SELECTへの参照を使用したJSONサーバーURLの作成に関する問題が1つありました(例:$(this).val())[:selected属性を指定する必要があります]。提案された更新を含めるために、スクリプトを少し変更しました。初期コードをありがとう。

<script>
$(document).ready(function() 
{
    $('#dd1').change(function() { fillOptions('dd1', 'dd2'); });
    $('#dd2').change(function() { fillOptions('dd2', 'dd3'); });
});

function fillOptions(parentId, ddId) 
{
    var dd = $('#' + ddId);
    var jsonURL = 'json/options?dd=' + ddId + '&val=' + $('#' + parentId + ' :selected').val();
    $.getJSON(jsonURL, function(opts) 
    {
        $('>option', dd).remove(); // Clean old options first.
        if (opts) 
        {
            $.each(opts, function(key, value) 
            {
                dd.append($('<option/>').val(key).text(value));
            });
        } 
        else 
        {
            dd.append($('<option/>').text("Please select parent"));
        }
    });
}
</script>
3
StephenB