2

I got a problem with JSF, hope someone can help me out. I have a Facelets xhtml page, with a SessionScoped managed bean. When a commandbutton is pressed on the page, a method is invoked in the bean, which dinamically creates another form on the page, with another commandbutton. That works very well so far, but when the newly created button is pressed on the page it somehow calls the action method twice. Here are the code samples from my backing bean:

The method which dynamically creates the new form, and works fine: (I used setActionExpression to bind an action to the button)

public void doCreateScreen() {
    FacesContext context = FacesContext.getCurrentInstance();
    Application application = context.getApplication();

    panelGrid.getChildren().clear();

    HtmlPanelGrid checkBoxGrid = (HtmlPanelGrid) application
            .createComponent(HtmlPanelGrid.COMPONENT_TYPE);
    checkBoxGrid.setColumns(columnNumber + 1);
    checkBoxGrid.getChildren().clear();

    for (int i = 1; i < rowNumber + 1; i++) {
        for (int j = 1; j < columnNumber + 1; j++) {
            HtmlSelectBooleanCheckbox tmpCheckBox = (HtmlSelectBooleanCheckbox) application
                    .createComponent(HtmlSelectBooleanCheckbox.COMPONENT_TYPE);
            String id = String.valueOf(i * columnNumber + j);
            tmpCheckBox.setId("box" + id);
            tmpCheckBox.setValue(true);
            checkBoxGrid.getChildren().add(tmpCheckBox);
        }
    }

    HtmlCommandButton createSeatsButton = (HtmlCommandButton) application
            .createComponent(HtmlCommandButton.COMPONENT_TYPE);
    createSeatsButton.setValue("Create Screen");

    MethodExpression createSeats = application.getExpressionFactory()
            .createMethodExpression(context.getELContext(),
                    "#{screencontroller.doCreateSeats}", null,
                    new Class<?>[0]);
    createSeatsButton.setActionExpression(createSeats);

    panelGrid.getChildren().add(checkBoxGrid);
    panelGrid.getChildren().add(createSeatsButton);

}

And this method which is called twice:

    public void doCreateSeats() {

        try {
            screen = screenOperator.createScreen(screen);

            for (int i = 1; i < rowNumber + 1; i++) {
                for (int j = 1; j < columnNumber + 1; j++) {
                    Seat seat = new Seat();
                    seat.setRow(i);
                    seat.setSeatNumber(j);
                    seat = screenOperator.createSeat(seat,
                            screen.getIdScreen());
                }
            }

            panelGrid.getChildren().clear();

        } catch (MovieTicketsException e) {
            // TODO
            e.printStackTrace();
        }

}

And the xhtml source:

        <div class="addform">
    <h1>Add new screen</h1>

    <h:form prependId="false">
        <h:panelGrid columns="2">
            <h:outputText value="Description:"></h:outputText>
            <h:inputText value="#{screencontroller.screen.description}"
                title="Description" id="Description" required="true"
                class="inputfield">
                <f:validateLength minimum="1" maximum="255"></f:validateLength>
            </h:inputText>


            <h:outputText value="Rows:"></h:outputText>
            <h:selectOneMenu value="#{screencontroller.rowNumber}" title="Rows"
                id="Rows" required="true" class="inputfield">
                <f:selectItems value="#{screencontroller.rowsSelectItems}">
                </f:selectItems>
            </h:selectOneMenu>

            <h:outputText value="Seats in a row:"></h:outputText>
            <h:selectOneMenu value="#{screencontroller.columnNumber}"
                title="Columns" id="Columns" required="true" class="inputfield">
                <f:selectItems value="#{screencontroller.rowsSelectItems}">
                </f:selectItems>
            </h:selectOneMenu>

            <h:outputLabel></h:outputLabel>
            <h:commandButton action="#{screencontroller.doCreateScreen}"
                value="Submit"></h:commandButton>

        </h:panelGrid>
    </h:form> <h:message for="Description" class="errormsg"></h:message> <h:message
        for="Cinema" class="errormsg"></h:message></div>

    <div class="listdiv"><h:form prependId="false">
        <h:panelGrid binding="#{screencontroller.panelGrid}" columns="1">
        </h:panelGrid>
    </h:form></div>

    </div>

I've just started learning jsf, so maybe i'm doing somthing really wrong, but i would be very thankful if someone could explain this.

Thanks

superuserSM
  • 21
  • 1
  • 2
  • some suggestions. try debugging the request using firebug addons, whether it's submitted twice. try debugging the the action method whether it's called twice. try to consider putting the new button component in the facelet rather in the source code and make use of the rendered attribute. benefits are good when placed in the facelet where you can do easy maintenance, good readability, easy reload, easily reused. – Bertie Nov 08 '11 at 03:41
  • It is bad practice to directly manipulate HTML/DOM from your controller (MB). Model your Screen into a POJO, use components that accept Lists as values and displays it's items (i.e. dataTable). Use ajax and dialogs to provide better UX. Also try to learn as soon as possible rich JSF component suites. I suggest Primefaces. – Yamada Jan 28 '14 at 16:19

0 Answers0