0

I have a problem again with JSF. I am still learning and your help is much apreciated.

<h:form>
    <h:selectOneMenu value="#{productBean.productName}">
        <f:selectItems value="#{productBean.pizza}" var="pizza" itemValue="#{pizza}" itemLabel="#{pizza.name}" />
        <f:ajax listener="#{productBean.valueChanged(pizza)}" render="pizzaResult" />
    </h:selectOneMenu>
    <h:commandButton value ="Dodaj do zamówienia"/>
    <h:outputText id="pizzaResult" value="#{productBean.message}" />
</h:form>

I just want to call the metod valueChanged with the parameter of custom object: Product. This is the method:

public void valueChanged(Product prod)
{
    if(prod.getIs_available() == 1)
        message = "yes";
    else
        message = "no";
}

I want it to verify if the product is available. And print it in an outputText tag. I think the problem is in HTML because all data reqested are Strings, and I cannot send an Product in such way. Should I use a converter? How it should look like? I don't know much about converters and the working example of ProductConverter will clear my mind. THanks in advance.

Mateusz Gaweł
  • 673
  • 1
  • 8
  • 22

3 Answers3

0

From the documentation of the listener attribute:

signature must match public void processAjaxBehavior(javax.faces.event.AjaxBehaviorEvent event) throws javax.faces.event.AbortProcessingException

So you need to change your valueChanged method like this:

public void valueChanged(AjaxBehaviorEvent ev)
{
    if(this.getIs_available() == 1)
        message = "yes";
    else
        message = "no";
}

However a cleaner approach would be to use a custom Validator.

dratewka
  • 2,104
  • 14
  • 15
0

(I still have a question. Please read) I think I was able to resolve it myself like this: (products is an arraylist with products. Every product has field like name or is_available got from the database in the constructor of the productBean. I iterated through the list looking for the right name and then checked if its available. if not i set right message)

    <h:selectOneMenu value="#{productBean.productName}">
        <f:selectItems value="#{productBean.drink}" var="drink" itemValue="#{drink.name}" itemLabel="#{drink.name}" />
        <f:ajax listener="#{productBean.valueChanged(productBean.productName)}" render="drinkResult" />
    </h:selectOneMenu>

public void valueChanged(String name)
{ 
    Iterator<Product> ie = products.iterator();
    while(ie.hasNext()) 
    {
        Product actualProd = ie.next();
        String prodName =actualProd.getName();
        int available =actualProd.getIs_available();
        if(prodName.equals(name) && available == 0)
        {
            System.out.println(prodName + available);
            message = " No rpoduct in store, sorry";
            break;
        }
        else
            message = "";
    }
}

But i am not sure it is the right way to do such things. What you think? I want to learn to write web application in Java EE as they should be written. "Ok it works" - it's not enough for me.

Mateusz Gaweł
  • 673
  • 1
  • 8
  • 22
  • As you've said yourself - you need a converter here. See [here](http://www.mkyong.com/jsf2/custom-converter-in-jsf-2-0/) for a tutorial. You basically need to fit the logic you have here in a `getAsObject` method. The only problem would occur if you have duplicate product names - if this is the case it's better to use a product id for the `itemValue`. – dratewka May 12 '13 at 11:21
  • Yep, the names ar only temporary because i didn't create a field for id yet in the bean – Mateusz Gaweł May 12 '13 at 11:32
  • You don't need a method that takes a parameter here, as your `productName` already *is* a property of `productBean`, that has been set by JSF, and thus available within standard method. – skuntsel May 12 '13 at 12:05
0

You don't need to pass an additional parameter in your listener, as the converted and validated value will be there in your bean. So, you can call you method on that object directly. What you need is to implement Converter and bind <h:selectOneMenu>'s value to your model class.

So, assuming your pizza is of type Pizza your setup will be the following.

The view:

<h:form>
    <h:selectOneMenu value="#{productBean.product}" converter="#{pizzaConverter}">
        <f:selectItems value="#{productBean.pizza}" var="pizza" itemValue="#{pizza}" itemLabel="#{pizza.name}" />
        <f:ajax listener="#{productBean.valueChanged}" render="pizzaResult" />
    </h:selectOneMenu>
    <h:commandButton value ="Dodaj do zamówienia"/>
    <h:outputText id="pizzaResult" value="#{productBean.message}" />
</h:form>

The bean:

@ManagedBean
@ViewScoped
public class ProductBean implements Serializable {
    private Pizza product;//getter+setter
    private String message;//getter
    public void valueChanged(AjaxBehaviorEvent abe) {
        message = ((product == null) || product.isAvailable()) ? "" : "Product temporarily unavailable";
    }
}

And you need to have a converter properly implemented. Example by me here, there are also numerous examples regarding converter usage on Stack Overflow.

Community
  • 1
  • 1
skuntsel
  • 11,624
  • 11
  • 44
  • 67
  • "And you need to have a converter properly implemented." that's the tricky part for me. – Mateusz Gaweł May 12 '13 at 11:42
  • You don't need to follow that workaround approach. It is both not nice and resource consuming. You *should* know how to implement the converter. – skuntsel May 12 '13 at 11:55
  • Pointed you at one example. It is really easy as you understand what's converter all about :) – skuntsel May 12 '13 at 12:01