2010-02-15 22 views
38

Supponiamo di avere tre controlli di elenchi a discesa denominati dd1, dd2 e dd3. Il valore di ogni elenco a discesa proviene dal database. Il valore di dd3 dipende dal valore di dd2 e il valore di dd2 dipende dal valore di dd1. Qualcuno può dirmi come posso chiamare servlet per questo problema?Popolamento di elenchi a discesa a cascata in JSP/Servlet

risposta

48

Ci sono fondamentalmente tre modi per raggiungere questo:

  1. Invia modulo ad un servlet durante l'evento onchange del 1 ° discesa (è possibile utilizzare Javascript per questo), lasciare che il servlet ottenere l'elemento selezionato di il 1 ° elenco a discesa come parametro di richiesta, consente di ottenere i valori associati del secondo menu a discesa dal database come Map<String, String>, lasciare che lo memorizzino nell'ambito della richiesta. Infine lascia che JSP/JSTL mostri i valori nel secondo menu a discesa. È possibile utilizzare JSTL (basta rilasciare jstl-1.2.jar nel tag /WEB-INF/lib) c:forEach per questo. È possibile eseguire il prepopolamento del primo elenco nel metodo doGet() dello Servlet associato alla pagina 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> 
    

    volta avvertimento è, tuttavia, che questa presenterà l'intero modulo e causare un "lampo di contenuti", che può essere un male per User Experience. Dovrai inoltre conservare gli altri campi nello stesso modulo in base ai parametri della richiesta. È inoltre necessario determinare nel servlet se la richiesta deve aggiornare un elenco a discesa (il valore di discesa figlio è null) o inviare il modulo effettivo.

  2. Stampa tutti i valori possibili del 2 ° e del 3 ° menu a discesa come oggetto Javascript e utilizza una funzione Javascript per compilare il secondo menu a discesa in base all'elemento selezionato del 1 menu a discesa durante l'evento onchange del 1 ° menu a discesa. Nessun modulo di invio e nessun ciclo del server è necessario qui.

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

    Un avvertimento è, tuttavia, che questo possa diventare inutilmente lungo e costoso quando si hanno un sacco di elementi. Immagina di avere 3 passaggi per ogni 100 articoli possibili, che significherebbe 100 * 100 * 100 = 1.000.000 di oggetti in JS. La pagina HTML crescerà di oltre 1 MB di lunghezza.

  3. Utilizzare XMLHttpRequest in Javascript per attivare una richiesta asincrona a un servlet durante l'evento onchange del 1 ° elenco a discesa, lasciare che il servlet ottenga l'elemento selezionato del 1 ° elenco a discesa come parametro di richiesta, consenta di ottenere i valori associati di il secondo menu a discesa dal database, restituirlo come XML o stringa JSON. Infine lascia che Javascript visualizzi i valori nel secondo elenco a discesa tramite l'albero DOM HTML (il metodo Ajax, come suggerito prima). Il modo migliore per farlo sarebbe utilizzare 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> 
    

    ..dove il Servlet dietro /json/options può avere questo formato:

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

    Qui, Gson è Google Gson che facilita la conversione di fullworthy oggetti Java a JSON e viceversa. Vedi anche How to use Servlets and Ajax?

+0

Impressionante codice BalusC. Se non ti dispiace, voglio fare un paio di domande sul tuo ultimo metodo. Nella tua funzione fillOption(), la riga $ .getJSON, sembra che tu invii una richiesta GET al servlet, ma dove specifichi l'url del servlet. Inoltre, il risultato che rimanda dal servlet ottiene lo store in "opts". Quindi è l'oggetto "opts" e l'oggetto JSON? Puoi spiegare questa riga: $ ('> option', dd) .remove(); un po 'di più? –

+0

@Harry Pham: '$ .getJSON' è documentato qui: http://api.jquery.com/jQuery.getJSON/ L'URL è solo'/json/options'. Vedi anche il testo (non guardare solo il codice). Puoi semplicemente scegliere qualunque URL tu voglia. Il 'opts' è infatti una stringa JSON restituita dal servlet. Vedi anche il link JSON per saperne di più.Se conosci bene Javabeans, allora JSON dovrebbe sembrare abbastanza familiare. L'opzione '$ ('>', dd) .remove()' rimuove tutte le opzioni precedenti dal menu a discesa, altrimenti sarebbe solo aggiunta, aggiunta, ecc. A proposito, se ti piacciono le risposte, basta svogliarlo. Vedo che non hai quasi mai votato. – BalusC

+0

Lo vedo ora, il primo parametro di getJSON è l'url. Sono un completo idiota. Riguardo alla questione del voto, mi dispiace. Non me n'ero nemmeno reso conto. Tornerò al mio vecchio post e aggiornerò il voto. Grazie mille. Se avrò più domande, tornerò e ti chiederemo. –

4

Potrebbe essere necessario più servlet per questo.

Servlet 1: carica i valori per il primo elenco a discesa dal database. Nella pagina JSP, costruire l'elenco a discesa. Sull'utente che seleziona un valore invia al servlet due.

Servlet 2: recupera il valore dal primo elenco ed esegue la ricerca nel database per i valori del secondo elenco. Costruisci la seconda lista. Quando l'utente seleziona il secondo valore, invialo al servlet 3.

Servlet 3: recupera il valore selezionato nel secondo menu a discesa ed esegue la ricerca nel database per ottenere i valori dell'ultima discesa.

Si consiglia di considerare AJAX per rendere la compilazione degli elenchi in modo trasparente agli utenti. jQuery ha alcuni plugin molto carini per renderlo abbastanza facile se si è disposti a farlo.


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

È possibile scrivere JavaScript che invia il modulo in caso onchange. Di nuovo, se usi una libreria esistente come jQuery sarà 10 volte più semplice.

+0

Sto avendo stessa idea frend e grazie per la cooperazione, ma io non so come posso chiamarlo mentre dd1 perde la sua attenzione – deven

+0

È possibile utilizzare un po 'di javascript per inviare il valore. Ne aggiungerò un po '. –

4

A giudicare dalla tua domanda, in realtà non stai utilizzando un framework web ma utilizzando servlet per il rendering di html.

Sarò gentile e dirò che sei circa un decennio dietro i tempi :), le persone usano JSP (e un framework web come struts) per questo genere di cose. Tuttavia, dopo averlo detto, ecco:

  1. Creare un campo nascosto nel modulo e impostare il valore su "1", "2" o "3" a seconda di quale menu a discesa deve essere compilato;
  2. Nel servlet, acquisire questo valore (request.getParamter()) e utilizzarlo come istruzione 'case'/if/else per restituire i valori dropdown appropriati.

Lo dirò di nuovo, basta usare un framework web o atleast plain old jsp per farlo.

3

Questa è stata una soluzione semplice impressionante. Mi piace quanto sia piccolo il codice JQuery e apprezzo molto il link all'API GSON. Tutti gli esempi hanno reso questa implementazione facile.

Si è verificato un problema relativo alla creazione dell'URL del server JSON con il riferimento al genitore SELECT (ad esempio $(this).val()) [necessario per specificare l'attributo :selected]. Ho modificato leggermente lo script per includere gli aggiornamenti suggeriti. Grazie per il codice iniziale.

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