jsf and submit()
I have the following jsf page.
<html>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix ="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix ="h" %>
<f:view>
<head>
<jsp:scriptlet>
String path = request.getContextPath() +"/css/styles.css";
</jsp:scriptlet>
<link href ="<jsp:expression>path</jsp:expression>" rel="stylesheet" type="text/css">
<f:loadBundle basename="bundle.messages" var="msgs"/>
<title><h:outputText value="#{msgs.windowTitleDeletingRows}"/></title>
</head>
<body>
<h:form>
<h:dataTable value="#{tableData.names}" var="name"
styleClass="names"
headerClass="namesHeader" columnClasses="last, first">
<h:column rendered="#{tableData.editable}">
<f:facet name="header">
<h:outputText value="#{msgs.deleteColumnHeader}"/>
</f:facet>
<h:selectBooleanCheckbox value="#{name.markedForDeletion}"
onchange="submit()"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.lastColumnHeader}"/>
</f:facet>
<h:outputText value="#{name.last}"/>
<f:verbatim>,</f:verbatim>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msgs.firstColumnHeader}"/>
</f:facet>
<h:outputText value="#{name.first}"/>
</h:column>
</h:dataTable>
<h:outputText value="#{msgs.editPrompt}"/>
<h:selectBooleanCheckbox onchange="submit()" value="#{tableData.editable}"/>
<h:commandButton value="#{msgs.deleteButtonText}" rendered="#{tableData.editable}"
action="#{tableData.deleteNames}" disabled="#{not tableData.anyNamesMarkedForDeletion}"/>
</h:form>
</body>
</f:view>
</html>
It contains a number of names that gets them form a bean named TableData. It includes a checkbox that when it is activated a series of checkboxes is diplayed next to the names. So when a user checks a checkbox a button named .delete selected names is activated.
I've taken this example from a tutorial. I want to ask two questions.
1.In this line :
<h:selectBooleanCheckbox onchange="submit()" value="#{tableData.editable}"/>
how the page understands that is should be submitted in the TableData bean? I mean I have nowhere a javascript functionsubmit()
2.The example works when I remove from the commandButton
<h:commandButton value="#{msgs.deleteButtonText}" rendered="#{tableData.editable}"
action="#{tableData.deleteNames}" disabled="#{not tableData.anyNamesMarkedForDeletion}"/>
therendered attribute. If this attribute is present then the method deleteNames is never invoked.Can someone explain me why is this happening?
Thanking you in advance
[4130 byte] By [
juanitaJa] at [2007-11-26 15:50:37]

# 16
My apologies. I wasn't being very clear. Maybe this will help me communicate better. I whipped up a test case to mimic the activity you are seeing.
I've created a request scope bean, that has an editable boolean property in it. It also has a value change listener (fired when the boolean checkbox is clicked), and an action method fired when the submit button is clicked. I then tied the rendered attribute on the submit button to the editable boolean.
Indeed, the action method does not get called.
I turned on my phase tracker, and here is what happens:
//I CLICK INTO THE APPLICATION - FIRST VISIT
[Jan 30, 09:37:03] DEBUG AppLogger.debug() - Request Bean Constructor
[Jan 30, 09:37:03] DEBUG AppLogger.debug() -boolean default is false
[Jan 30, 09:37:03] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:03] DEBUG AppLogger.debug() -returning boolean false
[Jan 30, 09:37:03] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:03] DEBUG AppLogger.debug() -returning boolean false
[Jan 30, 09:37:03] DEBUG AppLogger.debug() - AFTER RENDER_RESPONSE 6
//I CLICK ON THE CHECKBOX TO SET IT TRUE (AND FIRE VALUE CHANGE LISTENER)
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - BEFORE RESTORE_VIEW 1
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - AFTER RESTORE_VIEW 1
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - BEFORE APPLY_REQUEST_VALUES 2
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - Request Bean Constructor
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -boolean default is false
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -returning boolean false
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -returning boolean false
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - valueChangeLister (in request) fired!
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -setting boolean...
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - setEditable method called, setting boolean to true
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -Skip to render response...
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - AFTER APPLY_REQUEST_VALUES 2
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - BEFORE RENDER_RESPONSE 6
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:20] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:20] DEBUG AppLogger.debug() - AFTER RENDER_RESPONSE 6
//I CLICK ON THE NOW RENDERED SUBMIT BUTTON
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - BEFORE RESTORE_VIEW 1
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - AFTER RESTORE_VIEW 1
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - BEFORE APPLY_REQUEST_VALUES 2
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - Request Bean Constructor
[Jan 30, 09:37:52] DEBUG AppLogger.debug() -boolean default is false
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:52] DEBUG AppLogger.debug() -returning boolean false
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - AFTER APPLY_REQUEST_VALUES 2
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - BEFORE PROCESS_VALIDATIONS 3
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:52] DEBUG AppLogger.debug() -returning boolean false
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - AFTER PROCESS_VALIDATIONS 3
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - BEFORE UPDATE_MODEL_VALUES 4
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - setEditable method called, setting boolean to true
[Jan 30, 09:37:52] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:53] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - AFTER UPDATE_MODEL_VALUES 4
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - BEFORE INVOKE_APPLICATION 5
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - AFTER INVOKE_APPLICATION 5
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - BEFORE RENDER_RESPONSE 6
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:53] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:53] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:53] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:53] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - isEditable method in request bean called.
[Jan 30, 09:37:53] DEBUG AppLogger.debug() -returning boolean true
[Jan 30, 09:37:53] DEBUG AppLogger.debug() - AFTER RENDER_RESPONSE 6
This is what I was trying to explain in my last post. The request bean is created anew each time a request is made. The values from the last request are not carried over. Therefore, when JSF starts out on its new request, the editable boolean is false.
Because the editable boolean did not START as true, then JSF assumed it would not have rendered the command button. It cannot go back and check if it rendered the button, because it is constricted to the request level (i.e. it has absolutely no knowledge of what transacted last request). Since JSF doesn't think the button is rendered, it also knows that it could not have been clicked (and it's action method cannot be run).
Yes, the editable property gets set to true in the UPDATE_MODELS. But as far as JSF is concerned, that is what happened in the CURRENT request. And JSF will use that value when it renders the next page. Of course, by the time the next page gets submitted, it will have forgotten all about what happened in the current request! =)
Here's my request bean code:
public boolean isEditable() {
AppLogger.debug("isEditable method in request bean called.");
AppLogger.debug("returning boolean " + editable);
return editable;
}
public void setEditable(boolean bool) {
AppLogger.debug("setEditable method called, setting boolean to " + bool);
editable = bool;
}
public void fireChangeListener(ValueChangeEvent event)
throws AbortProcessingException {
AppLogger.debug("valueChangeLister (in request) fired!");
AppLogger.debug("setting boolean...");
setEditable(((Boolean)event.getNewValue()).booleanValue());
AppLogger.debug("Skip to render response...");
FacesContext.getCurrentInstance().renderResponse();
}
public String actionMethod() {
AppLogger.debug("Action Method (in request) fired!");
AppLogger.debug("boolean value is " + isEditable());
return "error";
}
So, I added the inputHidden component as BalusC suggested. Re-ran the test and indeed, nothing really changes.
So I moved JUST the editable boolean to the session scope. That worked perfectly. The biggest difference being, aside from the editable property now in session, is that editable returns true right from the start.
What does all this mean to you? Well, it means you have to put the editable boolean into the session scope. Sorry, I know you don't want to but that's the bottom line.
You can keep the session level pretty clean though. You can maintain the editable property just long enough to make your page work. When the action method is run, then you can invalidate the session or (less destructive) remove the property from the session. Because all you want is to get that action method to run!
Sorry this is long. But I hope you read it carefully and understand what JSF is doing. Feel free to seek clarification.
CowKing