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]
# 1

1) submit() is a built-in JavaScript function. This submit function doesn't actually call the commandButton on your page. It just submits the form (as if not clicking any button in particular).

2) I'm not sure I understand this question entirely. I think your presuming that the JavaScript submit() function should be calling the commandButton. But it doesn't. See 1.

The rendered attribute will literally remove the button from the current page, if it is false. In other words, it will not be even rendered. Check your HTML source when rendered is false, you will not see any "input type='submit'" tags.

Hope this helps,

CowKing

IamCowKinga at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 2
Thank you for your reply.As far as the rendered attribute is concerned my problem is that the returned value is true so the button is displayed however the method in the actionCommand in property action is never invoked.
juanitaJa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 3
Are there any errors on the page? Put <h:messages /> tag on your page somewhere.And, just to be sure, are you expecting the JavaScript submit to call your action?CowKing
IamCowKinga at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 4
I tried the h:messages but there are no errors..
juanitaJa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 5

Ok. I don't see any problems with the JSP. It should be working. Next steps...

Can you put a system.out.println or a logger message on the first line in the deleteNames action? This will let us know if the method is getting called at all, or if the method is not working. Then, please post the deleteNames method in your tableData bean.

Lastly, what scope (request or session) is the tableData bean in?

CowKing

IamCowKinga at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 6
I have debugs in the the delete method but these debugs never shown so the method is not invoked.the scope for the bean is request.
juanitaJa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 7

Hey I know this is probably a stupid question but sometimes its the obvious. Does your action method return string? I don't know what IDE your using but ctrl+click in Netbeans brings you to the method so that you can assure that it is linked to the right one.. I've had strange things happen when i put command buttons in between different form tags..

Message was edited by:

jbayuga

jbayugaa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 8
My delete method returns a null String but it never gets to this return since my method is never invoked. I believe my tags are fine because if set the rendered property equal to constant true and not to tableData.editable everythings works ok...
juanitaJa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 9

Try your TableData bean in session scope and see if the method gets called.

I suspect this is because you are setting the editable property in TableData on one request. Caching that result, and on the second request it has been reset (back to false). JSF probably won't process a button click that it doesn't think has been rendered.

CowKing

IamCowKinga at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 10
But the debug show that the rendered property is never false. If it was happening what you are saying I should see one debug with false.And I want my bean to has scope request and not session.
juanitaJa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 11

Not necessarily. A request scoped bean is destroyed at the end of the request. So the request occurs, the server responds, the bean is destroyed. You submit the form, but the request bean is destroyed. It recreates the necessary bean with default values (I'm guessing that rendered defaults to false).

You'd probably be ok if you moved just the rendered attribute into the session scope.

To be honest though, I'm not the best person to ask about the intricacies of the request scope. It's frustrated me a number of times as well. I think what happens, is that it doesn't quite work like people expect. The request bean from the page the user was just viewing is already destroyed by the time JSF will allow you to get at it. You know, while you're formulating your response to the input from the page. Which is generally when you need the data in the request scope (to formulate a good response).

You have to think of it opposite though. It's not, "what is the user telling the server." It's "what is the server telling the user" and you don't care what the user tells the server (cause it doesn't exist anymore). If you want the user to tell the server to do something, you will have to (at least) temporarily put that data in the session.

That's been my experience at least. I'm totally open to anyone correcting me (in fact, I'd like to hear it).

CowKing

Message was edited by:

IamCowKing

IamCowKinga at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 12
Put tableData.editable in a h:inputHidden field.
BalusCa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 13

I tried sth like that:

<h:inputHidden value="#{tableData.editable}" id="editable"/>

but it didint' work.

And as far as the IAmCowKing answer is concerned:

A request scoped bean is destroyed at the end of the request. So the request occurs, the server responds, the bean is destroyed. You submit the form, but the request bean is destroyed.

What do you mean?When the jsp is loaded the tableData.editable is not null it is TRUE.

juanitaJa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 14

Hmm OK, which JSF version are you using?

You can eventually d/l the most recent from http://javaserverfaces.dev.java.net

Edit

I was rereading the following:

> When the jsp is loaded the tableData.editable is not null it is TRUE.

Are you using boolean or Boolean for this property? You'd better to use boolean for this.

BalusCa at 2007-7-8 22:10:27 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 15
I am using JSF 1.1 and I am using boolean for the editable property.
juanitaJa at 2007-7-21 16:34:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 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

IamCowKinga at 2007-7-21 16:34:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 17

First of all I want to thank you for your answer.

I understand that each request is different and the values do not remain the same if a new request begins.

But my problem is that the value of my rendered attribute (the isEditable) it is TRUE.So why should I put this property in session?Since I have the value that I want.The rendered attribute it is true but still the commandButton does not submit the form.

By the way how will I put it in session, inside the bean correct?Not in the faces-config.xml.?

juanitaJa at 2007-7-21 16:34:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...
# 18

I really don't think your editable property is true when JSF needs it to be true.

Like I said, if the editable property STARTS as true, then it will be fine. I've tested it, and the action method gets called whenever the editable property starts the request as true.

If the editable property gets set to true LATER in the request, it won't work.

Probably the easiest way to put the editable property into the session is to put it in a session scoped bean. You can set up a session scoped bean the exact same way you set up a request scoped bean, except change the managed-bean-scope (in faces-config.xml) to session.

CowKing

IamCowKinga at 2007-7-21 16:34:37 > top of Java-index,Enterprise & Remote Computing,Web Tier APIs...