2010-02-15 158 views
38

Supongamos que tengo tres controles de lista desplegable llamados dd1, dd2 y dd3. El valor de cada lista desplegable proviene de la base de datos. El valor de dd3 depende del valor de dd2 y el valor de dd2 depende del valor de dd1. ¿Alguien puede decirme cómo llamo a servlet para este problema?Llenar listas desplegables en cascada en JSP/Servlet

Respuesta

48

Básicamente, hay tres maneras de lograr esto:

  1. Envíe el formulario a un servlet durante el evento onchange de la primera desplegable (se puede utilizar Javascript para esto), deja que el servlet obtener el elemento seleccionado de el primer menú desplegable como parámetro de solicitud, le permite obtener los valores asociados del segundo menú desplegable de la base de datos como Map<String, String>, deje que los almacene en el ámbito de la solicitud. Finalmente, deje que JSP/JSTL muestre los valores en el segundo menú desplegable. Puede usar JSTL (simplemente elimine jstl-1.2.jar en /WEB-INF/lib) c:forEach etiqueta para esto. Puede rellenar previamente la primera lista en el método doGet() del Servlet asociado a la página JSP.

    <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> 
    

    Una vez salvedad es sin embargo que esto va a someter la totalidad forma y provocar un "destello de contenido" que puede ser malo para la experiencia del usuario. También necesitará retener los otros campos en el mismo formulario en función de los parámetros de solicitud. También deberá determinar en el servlet si la solicitud es para actualizar un menú desplegable (el valor desplegable del elemento secundario es nulo) o para enviar el formulario real.

  2. Imprime todos los valores posibles del segundo y tercer desplegable como un objeto Javascript y utiliza una función Javascript para completar el segundo menú desplegable basado en el elemento seleccionado del primer menú desplegable durante el evento onchange del primer menú desplegable. No se envía ningún formulario y no se necesita un ciclo de servidor aquí. Sin embargo

    <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> 
    

    Una advertencia es que esto puede llegar a ser innecesariamente largo y costoso cuando se tiene una gran cantidad de artículos. Imagine que tiene 3 pasos de cada 100 elementos posibles, que significaría 100 * 100 * 100 = 1,000,000 de elementos en objetos JS. La página HTML crecerá más de 1 MB de longitud.

  3. Utilice XMLHttpRequest en Javascript para iniciar una solicitud asincrónica a un servlet durante el evento onchange del primer menú desplegable, deje que el servlet obtenga el elemento seleccionado de la primera lista desplegable como parámetro de solicitud, permita obtener los valores asociados de la segunda lista desplegable de la base de datos, devuélvala como cadena XML o JSON. Finalmente, permita que Javascript muestre los valores en el segundo menú desplegable a través del árbol HTML DOM (el modo Ajax, como se sugirió anteriormente). La mejor forma de hacerlo sería usando 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 la Servlet detrás /json/options podría tener este aspecto:

    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); 
    } 
    

    Aquí, GsonGoogle Gson es que facilita la conversión de fullworthy objetos Java a JSON y viceversa. Consulte también How to use Servlets and Ajax?

+0

Código impresionante BalusC. Si no te importa, quiero hacerte un par de preguntas sobre tu último método. En su función fillOption(), la línea $ .getJSON, parece que envía una solicitud GET al servlet, pero ¿dónde especifica la url del servlet? Además, ¿el resultado que devuelve el servlet get store está en 'opts'? Entonces, ¿es 'opta' y el objeto JSON? ¿Puedes explicar esta línea? $ ('> Option', dd) .remove(); ¿un poco más? –

+0

@Harry Pham: '$ .getJSON' está documentado aquí: http://api.jquery.com/jQuery.getJSON/ La URL es simplemente'/json/options'. También vea el texto (no solo mire el código). Solo puede elegir la URL que desee. El 'opts' es, de hecho, la cadena JSON devuelta por el servlet. También vea el enlace JSON para obtener más información al respecto.Si sabes que Javabeans es bueno, entonces JSON debería ser lo suficientemente familiar. El '$ ('> option', dd) .remove()' elimina todas las opciones previas del menú desplegable, de lo contrario solo se agregaría, anexaría, etc. Por cierto, si te gustan las respuestas, simplemente recípalas. Veo que casi nunca votaste. – BalusC

+0

Lo veo ahora, el primer parámetro de getJSON es la url. Soy un completo idiota Sobre lo de votar, lo siento. Ni siquiera me di cuenta de eso. Miraré atrás en mi publicación anterior y actualizaré la votación. Muchas gracias. Si tengo más preguntas, volveré y te preguntaré. –

4

Es posible que necesite varios servlets para esto.

Servlet 1: Cargue los valores de la primera lista desplegable de la base de datos. En la página JSP construye la lista desplegable. En el usuario seleccionando un valor enviar a servlet dos.

Servlet 2: recupera el valor de la primera lista y realiza la búsqueda en la base de datos de los valores de la segunda lista. Construye la segunda lista. Cuando el usuario selecciona el segundo valor, preséntelo al servlet 3.

Servlet 3: recupera el valor seleccionado en el segundo menú desplegable y realiza la búsqueda en la base de datos para obtener los valores del último menú desplegable.

Es posible que desee considerar AJAX para que la población de las listas se muestre sin problemas a los usuarios. jQuery tiene algunos complementos muy buenos para hacer esto bastante fácil si estás dispuesto a hacer eso.


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

Puede escribir código JavaScript que envía el formulario en el evento onchange. Nuevamente, si usa una biblioteca existente como jQuery, será 10 veces más simple.

+0

estoy teniendo Frend misma idea y gracias a la cooperación pero no sé cómo puedo llamarlo mientras DD1 pierde su enfoque – deven

+0

Puede utilizar un poco un javascript para presentar el valor. Añadiré algunos. –

4

A juzgar por su pregunta, en realidad no está utilizando un marco web, pero el uso de servlets para procesar html.

Seré amable y deciré que estás a una década de los tiempos :), la gente usa JSP (y un framework web como puntales) para este tipo de cosas. Sin embargo, una vez dicho esto, aquí va:

  1. crear un campo oculto en el formulario y definir el valor a '1', '2' o '3' en función de la cual se cae abajo a poblarse;
  2. En su servlet, capture este valor (request.getParamter()) y utilícelo como una instrucción 'case'/if/else para devolver los valores desplegables correspondientes.

Lo diré de nuevo, solo use un framework web, o al menos antiguo jsp antiguo para hacer esto.

3

Esa fue una solución simple impresionante. Me gusta lo pequeño que es el código JQuery y realmente aprecio el enlace a la API GSON. Todos los ejemplos hicieron de esto una implementación fácil.

Tuve un problema al construir la URL del servidor JSON con la referencia al elemento primario SELECT (por ejemplo, $(this).val()) [necesario para especificar el atributo :selected]. Modifiqué un poco el guión para incluir las actualizaciones sugeridas. Gracias por el código inicial.

<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> 
Cuestiones relacionadas