web-dev-qa-db-fra.com

Comment utiliser <h: selectBooleanCheckbox> dans <h: dataTable> ou <ui: repeat> pour sélectionner plusieurs éléments?

J'ai une page Facelets avec un <h:dataTable>. Dans chaque ligne, il y a un <h:selectBooleanCheckbox>. Si la case est cochée, l'objet derrière la ligne correspondante doit être défini dans le bean.

  1. Comment puis-je faire cela?
  2. Comment obtenir les lignes sélectionnées ou leurs données dans un bean de sauvegarde?
  3. Ou serait-il préférable de le faire avec <h:selectManyCheckbox>?
20
c0d3x

Votre meilleur pari est de lier le h:selectBooleanCheckbox valeur avec un Map<RowId, Boolean> propriété où RowId représente le type de l'identificateur de ligne. Prenons l'exemple d'un objet Item dont la propriété d'identifiant id est un 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}" />

qui doit être utilisé en combinaison avec:

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

et

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

    // ...
}

Vous voyez, la carte est automatiquement remplie avec le id de tous les éléments de table comme clé et la valeur de la case à cocher est automatiquement définie comme valeur de carte associée à l'élément id comme clé.

52
BalusC

Dans l'exemple suivant, j'utilise des cases à cocher pour sélectionner deux ou plusieurs produits afin de permettre à l'utilisateur de comparer les spécifications des produits sur une nouvelle page Web à l'aide de JSF 2.0.

Il m'a fallu un bon moment pour trouver le problème suivant (totalement évident maintenant bien sûr) alors j'ai pensé qu'il valait la peine d'être mentionné pour ceux qui essayent d'utiliser la pagination avec le code de BalusC ci-dessus (Belle réponse BalusC, beaucoup plus simple que je ne l'avais imaginé).

Si vous utilisez la pagination, vous obtiendrez des pointeurs null à la ligne:

if (vérifié.get (item.getId ()))

-dans le code de BalusC ci-dessus.

En effet, seules les cases à cocher affichées sont ajoutées à la carte (doh; slap front). Pour les produits dont les cases à cocher ne sont jamais affichées, en raison de la pagination, cette ligne entraînera une erreur de pointeur nul et une vérification doit être ajoutée pour ignorer ces pointeurs nuls (en supposant que toutes les cases à cocher ne sont pas cochées au chargement de la page). Pour que l'utilisateur coche une case, il doit afficher la page de pagination afin que tout fonctionne bien après.

Si certaines ou toutes les cases à cocher doivent être cochées lors du chargement de la première page, cela ne vous sera d'aucune aide ... vous devrez les ajouter manuellement à la carte pour qu'elles s'affichent correctement au chargement de la page. .

Remarque: étant donné que j'utilise un objet JPA 'Entity class from database', j'ai également dû utiliser @Transient pour l'ID dans ma ProductTbl Entity Class car toutes les variables sont considérées comme des colonnes dans la base de données par JPA, par défaut, sauf si elles sont préfixées par @Transient . J'utilise également un deuxième lien pour réinitialiser les cases à cocher, qui appelle clearSelections (), et mon "soumettre" est un lien appelant compareSelectedProducts () plutôt qu'un bouton Soumettre.

Le code complet est le suivant:

Dans la classe d'entité "ProductTbl" dérivée de la base de données:

@Transient
private Long id;

public Long getId()
{
    return id;
}

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

Dans le bean de sauvegarde '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";
}

Dans la page Web 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>

Dans le fichier 'faces-config.xml':

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

Une façon d'envoyer un paramètre via <h:selectBooleanCheckbox> Est de l'envoyer via le titre de la case à cocher. Dans le ValueChangeListener, vous pouvez l'obtenir à partir du composant en utilisant un getAttributes().get("title"). Cela aide dans les cas où vous souhaitez envoyer une valeur id en tant que paramètre (par opposition à l'index de ligne sélectionné).

1
Mallika