pages.xml action method fired on ajax requests - must be wro
gothmog Oct 17, 2007 4:53 AMHi,
I have just spent the whole day re-structuring my seam application to make use of the action method on a page element in pages.xml only to find to my dismay that the action method fires not only on redirects to the page (as it should) but also on ajax callbacks.
This should not be the case as the action method on the page should fire on the first time load of the page only, thus a perfect place to put initial model setup logic (or to ensure the model is setup so that pages.xml can redirect elsewhere if not, say by using an if-outcome etc), whilst all the ajax calls are technically working with the same page via postbacks (and hence don't need the setup logic).
What this means is that the setup logic that I put into action method gets called ALL the time effectively eliminating the work of my ajax postback to change the model in order to change the display. i.e. during the rendering phase the setup logic gets called again, changing the model back to the initial page load state (and un-doing the work the ajax call did in the first place).
My specific example is as follows
pages.xml fragment
<page view-id="/pm_ncrv.xhtml" action="#{maintainComponent.setupRelationshipsView}" login-required="true"> ... </page>
Now there is an ajax callback in the page as follows
<a4j:outputPanel id="childAttributes"> <s:div rendered="#{not attributeProps.show}"> <a4j:commandLink action="#{maintainComponent.addNewChildComponent}" immediate="true" value="Add new child component" reRender="childAttributes" oncomplete="initFileUploads()" styleClass="button" /> </s:div> <s:div rendered="#{attributeProps.show}"> ... </s:div> </a4j:outputPanel>
Now the setup method setupRelationshipsView() called in the action parameter of pages.xml does the following so that the ajax panel childAttributes is not rendered when you first redirect to the page:
public void setupRelationshipsView() { log.info("setupRelationshipsView()"); component = null; attributeProps = new AttributeProperties(); attributeProps.setLegendText("Child Component Attributes"); attributeProps.setReadOnly(false); attributeProps.setShow(false); }
The ajax call addNewChildComponent() wants to show the child attributes panel inline so that a new child component can be added so it does this:
public void addNewChildComponent() { log.info("addNewChildComponent():mainComponent=" + mainComponent); if (mainComponent == null) { facesMessages.add("Main component not in correct state. " + "Child component could not be added. Please check log for errors."); log.error("addNewChildComponent():mainComponent not " + "in correct state:mainComponent=" + mainComponent); } else { if (mainComponent.getChildComponents() == null) { mainComponent.setChildComponents(new ArrayList<ISISComponent>()); } component = new ISISComponent(); component.setParentComponent(mainComponent); imageHolder = component; attributeProps = new AttributeProperties(); attributeProps.setLegendText("Add new child component attributes"); attributeProps.setReadOnly(false); attributeProps.setShow(true); } }
In other words it sets the show flag on attributeProps so that the inline panel is displayed. BUT... from the logs I see that the pages.xml action method gets called after the ajax call which resets the model variable attributeProps so that the inline panel is never displayed.
21:38:43,044 INFO [MaintainComponentAction] addNewChildComponent():mainComponent=model.ISISComponent@780767 21:38:43,053 INFO [MaintainComponentAction] setupRelationshipsView()
How does one stop the pages.xml from firing on ajax callbacks? I would consider this a major architectual flaw if this could not be done!! HELP!
Thanks
Troy
Seam 2.0.0 BETA
RichFaces 3.1.0
Jboss 4.2.0.GA