19

Mam stronę Facelets z <h:dataTable>. W każdym rzędzie znajduje się <h:selectBooleanCheckbox>. Jeśli pole wyboru jest zaznaczone, obiekt znajdujący się za odpowiednim wierszem powinien zostać ustawiony w komponencie bean.Jak korzystać z <h: selectBooleanCheckbox> w <h:dataTable> lub <ui:repeat>, aby wybrać wiele elementów?

  1. Jak to zrobić?
  2. Jak uzyskać zaznaczone wiersze lub ich dane w komponencie bean?
  3. A może lepiej zrobić to z <h:selectManyCheckbox>?
+0

Hi BalusC, to nie działa na paginacji, żadnego śladu? –

Odpowiedz

48

Najprościej jest wiązać wartość h:selectBooleanCheckbox z właściwością Map<RowId, Boolean> gdzie RowId reprezentuje typ identyfikatora wiersza. Weźmy przykład, że masz do Item obiekt, którego identyfikator nieruchomość id jest Long:

<h:dataTable value="#{bean.items}" var="item"> 
    <h:column> 
     <h:selectBooleanCheckbox value="#{bean.checked[item.id]}" /> 
    </h:column> 
    ... 
</h:dataTable> 
<h:commandButton value="submit" action="#{bean.submit}" /> 

który ma być używany w połączeniu z:

public class Item { 
    private Long id; 
    // ... 
} 

i

public class Bean { 
    private Map<Long, Boolean> checked = new HashMap<Long, Boolean>(); 
    private List<Item> items; 

    public void submit() { 
     List<Item> checkedItems = checked.entrySet().stream() 
      .filter(Entry::getKey) 
      .map(Entry::getValue) 
      .collect(Collectors.toList()); 

     checked.clear(); // If necessary. 

     // Now do your thing with checkedItems. 
    } 

    // ... 
} 

Mapa jest automatycznie wypełniana id wszystkich pozycji tabeli jako kluczem, a wartość pola wyboru jest automatyczna cally ustawić jako wartość mapy związaną z pozycją id jako klucz.

+0

Czy nie byłoby jeszcze łatwiej użyć 'mapy' typu' ', więc potrzebujesz tylko iterować mapę zamiast całej listy? –

+0

@ Markus: to nie jest możliwe. '' obsługuje tylko wartości 'boolean' lub' Boolean'. – BalusC

+1

to tabela danych, a przycisk powinien być w tej samej formie? możesz przesłać więcej szczegółów do widoku lub tylko przycisk powinien znajdować się w formularzu. –

1

Jednym ze sposobów wysłania parametru poprzez <h:selectBooleanCheckbox> jest wysłanie go przez tytuł pola wyboru. W wersji ValueChangeListener możesz pobrać ją ze składnika za pomocą getAttributes().get("title"). Pomaga to w przypadkach, w których chcesz wysłać wartość id jako parametr (w przeciwieństwie do wybranego indeksu wiersza).

+0

Nie jestem pewien, co masz na myśli, mówiąc "w przeciwieństwie do wybranego indeksu wiersza", ale jeśli celujesz w moją odpowiedź, potem zauważ, że nigdzie nie przechodzę obok indeksów wierszy. Tylko identyfikatory wybranych elementów. – BalusC

3

W poniższym przykładzie używam pól wyboru, aby wybrać dwa lub więcej produktów, aby umożliwić użytkownikowi porównanie specyfikacji produktu na nowej stronie internetowej przy użyciu JSF 2.0.

Zajęło mi sporo czasu, aby znaleźć następujący problem (oczywiście całkowicie oczywiste), więc pomyślałem, że warto wspomnieć o tych, którzy próbują korzystać z paginacji z kodem BalusC powyżej (dobra odpowiedź BalusC, o wiele prostsze niż kiedykolwiek wyobrażałem to byłoby).

Jeśli używasz paginacji dostaniesz nullpointers na linii:

if (checked.get (item.getId()))

-in kodu BalusC jest powyżej.

Dzieje się tak dlatego, że tylko wyświetlane pola wyboru są dodawane do mapy (doh, slap czoło). W przypadku produktów, których pola wyboru nie są wyświetlane, z powodu paginacji, linia ta spowoduje błąd wskaźnika pustego i konieczne będzie dodanie kontroli, aby zignorować te wskaźniki zerowe (zakładając, że wszystkie pola wyboru są odznaczone przy ładowaniu strony). Aby zaznaczyć pole wyboru, użytkownik musi wyświetlić stronę stronicowania, aby wszystko działało po niej.

Jeśli zaznaczono niektóre lub wszystkie pola wyboru przy pierwszym ładowaniu strony, nie będzie to dla ciebie pomocne ...będziesz musiał ręcznie dodać je do mapy, aby mogły być wyświetlane poprawnie po wczytaniu strony.

Uwaga: ponieważ używam obiektu JPA 'Entity class from database', potrzebowałem również użyć @Transient dla id w mojej klasie ProductTbl Entity, ponieważ wszystkie zmienne są domyślnie uznawane za kolumny w bazie danych przez JPA, chyba że prefiks z @Transient. Używam również drugiego łącza, aby zresetować pola wyboru, które wywołują clearSelections(), a moje "submit" to link wywołujący compareSelectedProducts() zamiast przycisku Submit.

pełny kod jest następujący:

W klasie jednostki ProductTbl 'pochodzi z bazy danych:

@Transient 
private Long id; 

public Long getId() 
{ 
    return id; 
} 

public void setId(Long id) 
{ 
    this.id = id; 
} 

w podłożu fasoli 'ProductSelection':

private Map<Long, Boolean> checked = new HashMap<Long, Boolean>(); 
private String errorMessage = ""; 
// List of all products. 
private List<ProductTbl> products; 
// List of products to compare. 
private List<ProductTbl> compareProducts; 

// Setters and getters for above... 

public String compareSelectedProducts() 
{ 
    // Reset selected products store. 
    compareProducts = new ArrayList(); 

    for (ProductTbl item: products) 
    { 
     // If there is a checkbox mapping for the current product then... 
     if(checked.get(item.getId()) != null) 
     { 
      // If checkbox is ticked then... 
      if (checked.get(item.getId())) 
      { 
       // Add product to list of products to be compared. 
       compareProducts.add(item); 
      } 
     } 
    } 

    if(compareProducts.isEmpty()) 
    { 
     // Error message that is displayed in the 'ErrorPage.xhtml' file. 
     errorMessage = "No Products selected to compare specifications. Select two or more products by ticking the check box in the second column 'Cmpr'"; 
     return "process_ErrorPage"; 
    } 

    // Rest of code to get product specification data ready to be displayed. 

    return "process_CompareSelected"; 
} 

public String clearSelections() 
{ 
    // Untick all checkbox selections. 
    checked.clear(); 

    return "process_MainSearchResult"; 
} 

W Strona WWW JSF "MainSearchResult.xhtml":

<h:commandLink action="#{productSelection.compareSelectedProducts()}" value="Cmpr Specification Comparison Table" /> 
<h:commandLink action="#{productSelection.clearSelections()}" value="Clear Selected" /> 

<h:dataTable value="#{productSelection.products}" rows="#{productSelection.numberRowsToDisplay}" first="#{productSelection.rowStart}" var="item" headerClass="table-header" > 
    <h:column> 
     <f:facet name="header"> 
      <h:outputText style="font-size:12px" value="Cmpr" /> 
     </f:facet> 
     <div style="text-align:center;" > 
      <h:selectBooleanCheckbox value="#{productSelection.checked[item.id]}" /> 
     </div> 
    </h:column> 
</h:dataTable> 

W 'faces-config.xml' pliku:

<navigation-rule> 
    <navigation-case> 
     <from-outcome>process_MainSearchResult</from-outcome> 
     <to-view-id>/MainSearchResult.xhtml</to-view-id> 
    </navigation-case> 
</navigation-rule> 
<navigation-rule> 
    <navigation-case> 
     <from-outcome>process_CompareSelected</from-outcome> 
     <to-view-id>/CompareSelected.xhtml</to-view-id> 
    </navigation-case> 
</navigation-rule> 
<navigation-rule> 
    <navigation-case> 
     <from-outcome>process_ErrorPage</from-outcome> 
     <to-view-id>/ErrorPage.xhtml</to-view-id> 
    </navigation-case> 
</navigation-rule>