Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write to a map property in an h:inputText in h:dataTable

Tags:

jsf

jsf-2.2

I want to add an input text where the user can edit a quantity in an h:dataTable

<h:dataTable id="checkout_table" value="#{cartController.cart.entrySet()}"
    var="item" >
    <h:column>
        <f:facet name="header">Movie</f:facet>
        #{item.key.title} - #{item.key.getAvailable()}
    </h:column>
    <h:column>
        <f:facet name="header">Quantity</f:facet>
        <h:inputText id="quantity"
            value="#{item.value}" redisplay="true"
            converterMessage="Please provide an integer" required="true"
            requiredMessage="Please enter a quantity">
            <!-- <f:validateLongRange minimum="1"
                maximum="#{item.key.getAvailable()}" />
                    this validation must be performed on set-->
            <f:ajax event="blur" render="quantityMessage" />
        </h:inputText>
    </h:column>
    <h:column><h:commandButton value="edit"
        action="#{cartController.addMovieToCart(item.key, item.value)}" />
    </h:column>
    <h:column><h:commandButton value="delete"
        action="#{cartController.removeMovie(item.key)}" />
    </h:column>
    <h:column><h:message id="quantityMessage" for="quantity" /></h:column>
</h:dataTable>

As it is now the exception is thrown The class 'java.util.LinkedHashMap$Entry' does not have a writable property 'value'. I have read various things on binding but can't quite wrap my head around them. What should I do to define a getter and setter for this input filed ? Is there some other component I could use ?

If the validation could be handled also that would be appreciated !

EDIT: after the @BalusC answer I managed to read and write to the map - with one caveat - I get a CCE java.lang.String cannot be cast to java.lang.Integer in the bean

private Map<Movie, Integer> cart = new LinkedHashMap<>();

public String addMovieToCart(Movie movie, Integer quantity) {
    if (quantity > movie.getAvailable()) {
        String message = "Available copies are " + movie.getAvailable();
        FacesContext.getCurrentInstance().addMessage(null,
            new FacesMessage(FacesMessage.SEVERITY_ERROR, message, null));
        return null;
    }
    Integer ordered = cart.get(movie); // CCE here !
    // etc
}

This was solved finally by:

<h:inputText id="quantity"
    value="#{cartController.cart[item.key]}"
    converterMessage="Please provide an integer" required="true"
    requiredMessage="Please enter a quantity" converter="javax.faces.Integer">

Notice the converter - apparently JSF transforms map elements to String ? One has to explicitly convert to integer

Validation without omnifaces though seems tough (due to render/view time)

like image 787
Mr_and_Mrs_D Avatar asked Dec 16 '22 01:12

Mr_and_Mrs_D


1 Answers

If you want to have a writable Map value in EL, then you need the brace notation
#{map[entry.key]} wherein you pass the key as another variable. The #{entry.value} is indeed not going to work as this is read-only, as indicated by the exception.

So, this should do in your particular case:

<h:dataTable value="#{cartController.cart.entrySet()}" var="item">
    ...
    <h:inputText ... value="#{cartController.cart[item.key]}" />

As to the valiator, this answer applies: Using validator with a variable attribute in ui:repeat

By the way, the redisplay attribute isn't supported by <h:inputText>. Perhaps you're confusing with <h:inputSecret>?

like image 178
BalusC Avatar answered Jan 17 '23 03:01

BalusC