2012-02-27 12 views
7

Sembra che ogni volta che imparo una nuova piattaforma, devo risolvere lo stesso vecchio problema: Aggiornare le scelte in un menu a discesa dopo la modifica di un altro menu a discesa, utilizzando Ajax. Questa volta il framework è Wicket.Wicket Ajax aggiorna un elenco a cascata

Ho due entità che chiamerò Foo e Bar, e ogni Foo ha una categoria, che è un enum interno a Foo. Inoltre, esiste un FooDAO con metodi sovraccarichi find(): la versione no-arg restituisce tutti i Foo nel DB, o una versione con un "filtro" parametrico di Tipo Foo che restituisce il filtro di corrispondenza Foo in valori non nulli.

Il client desidera associare Foos a Bars durante la creazione di una nuova barra, ma per filtrare Foos per categoria prima di aggiungerne uno. Quindi supponiamo che esistano già una manciata di Foo, ognuno con una categoria. Un utente va alla pagina Crea bar e alla sezione per aggiungere un nuovo Foo: Dropdown A elenca le categorie e, in base alla scelta di una categoria, Dropdown B dovrebbe mostrare l'elenco di Foo disponibile in quella categoria, tramite un aggiornamento Ajax. Nota che nessuna categoria è selezionata, il menu a discesa B dovrebbe mostrare tutti i Foo disponibili.

mio HTML sembra un po 'come questo:

<form wicket:id="createBarForm"> 
<div> 
    <label>Category</label> 
    <select wicket:id="category"> 
    </select> 
</div> 
<div> 
    <label>Available Foo(s)</label> 
    <select class="xlarge" wicket:id="selectedFoo"> 
    </select> 
</div> 
<button style="float:right;">Add</button> 

<!-- and more Bar related fields --> 
</form> 

(. Il pulsante finirà per ottenere un proprio ID e il comportamento, ma in questo momento l'attenzione è sulle liste)

Ecco il Java lato (nel metodo di costruzione della pagina):

createBarForm = new Form<Bar>("createBarForm", 
      new CompoundPropertyModel<Bar>()); 

    final List<Foo> availableFoo = fooDao.find(); 

    final FormComponent<Foo> selectedFoo = 
      new DropDownChoice<Foo>("selectedFoo", 
        Model.of(new TechnologyFoo()), availableFoo); 

    Foo.Category categoryStandin = null; 

    final FormComponent<Foo.Category> fooCategory = 
      new DropDownChoice<Foo.Category> 
       ("fooCategory", Model.of(categoryStandin), 
         Arrays.asList(Foo.Category.values())); 

    fooCategory.add(new AjaxFormComponentUpdatingBehavior("onchange") { 
     private static final long serialVersionUID = 1L; 
     @Override 
     protected void onUpdate(AjaxRequestTarget target) { 
      // re-set the form component 
      availableFoo.clear(); 
      ((DropDownChoice<Foo>)selectedFoo).setChoices(availableFoo); 
      createBarForm.remove(selectedFoo); 

      Foo.Category newSelection = 
        fooCategory.getModelObject(); 
      if (newSelection != null) { 
       Foo filter = new Foo(); 
       filter.setCategory(newSelection); 
       availableFoo.addAll(fooDao.find(filter)); 
      } 
      else { 
       availableFoo.addAll(fooDao.find()); 
      } 
      // re-fresh the form component 
      ((DropDownChoice<Foo>)selectedFoo).setChoices(availableFoo); 
      createBarForm.add(selectedFoo); 
     } 
    }); 

    createBarForm.add(fooCategory); 
    createBarForm.add(selectedFoo); 

    // etc..... 

non ho mostrato le mie logger.debug chiamate, ma con loro sono in grado di dimostrare che il newSelection è essere catturato correttamente e il DAO restituisce l'elenco previsto di Foo. Inoltre, l'elenco avaliableFoo contiene anche i valori richiesti. Tuttavia, Dropdown B mostra sempre l'elenco completo di Foo, indipendentemente da della selezione della categoria.

+1

Visto che hai la risposta giusta, questo è un sidenote: avrei probabilmente spostare il codice di aggiornamento di selezione/scelta nei rispettivi modelli dei componenti scelta discesa e basta fai la chiamata 'target.addComponent()' nel metodo 'onUpdate()', il tuo codice sarà molto più facile da leggere e conservare. – biziclop

risposta

5

Devi aggiungere i tuoi DropDown all'AjaxRequestTarget altrimenti non verrebbero aggiornati.

come in

target.add(selectedFoo); 
+0

Devo anche aggiungere 'selectedFoo.setOutputMarkupId (true);' ma sembra che funzioni. – cobaltduck

Problemi correlati