I have a print icon that renders the printable version of the form.
<af:link id="printButton" icon="/images/printer.png">
<af:showPrintablePageBehavior/>
</af:link>
This part works properly, but after you close the tab created by the <af:showPrintablePageBehavior/>
any attempts to redirect to a new page creates a new browser tab.
The button doing the redirect is defined thusly,
<af:button text="Search" action="#{backing.searchAction}"
partialSubmit="false" immediate="true" id="ab1" />
public String searchAction() {
return "search"
}
"search"
is a navigation-rule, which is defined in the faces-config.xml
and works properly if you do not invoke <af:showPrintablePageBehavior/>
before clicking the button.
I have tried using ExternalContext.redirect(page)
. I have also tried defining the targetFrame
attribute to _self
and _parent
for the <af:button>
. The miss-behavior is consistent with each of these approaches.
The root of all evil in your example is the immediate="true"
attribute. If you just remove it, you'll get your problem solved.
However, in order to explain why, let's first start with the <af:showPrintablePageBehaviour>
component and the trinidad-config.xml
file (which is nested within the WEB-INF
folder).
The trinidad-config.xml
file lists an element, called <output-mode>
. By default, it's not there, but you can add it manually. The element supports three values:
"default"
(or null
): the default output mode"printable"
: an output mode suitable for printable pages"email"
: an output mode suitable for e-mailing a page's contentIn order to have a page content displayed as a printable, the output-mode
is changed (usually by the underlying framework) to "printable"
. So, every time you click on your <af:link>
component, the <output-mode>
value is set to "printable"
.
The good thing about trinidad-config.xml
is that we are allowed to use EL expressions within, which means that we can dynamically change the value of the <output-mode>
element. For example, the value can be read from a @ManagedBean
:
<output-mode>#{printableBehaviorBean.outputMode}</output-mode>
The been itself can be a completely simple (@RequestScoped
) bean. Note that I'm using annotations instead of XML-based configuration, because you mentioned you're using ADF 12c, which is built on the top of JSF-2.
@RequestScoped
@ManagedBean(name = "printableBehaviorBean")
public class PrintableBehaviorBean {
private String outputMode;
public void setOutputMode(String outputMode) {
this.outputMode = outputMode;
}
public String getOutputMode() {
return outputMode;
}
}
Then, we can inject this bean within another bean, which will help us navigate to the "search"
activity when the Search
button is pressed. The bean will have a nested @ManagedProperty
member, which will hold an instance of the preceding printableBehaviorBean
bean. Also, the navigationBean
will introduce a search()
method, which we'll be referred from the Search
button's action
attribute.
The trick here's that before actually returning the navigation outcome, we'll change the value of the outputMode
property in the printableBehaviorBean
. Remember that this new value will overwrite the existing <output-mode>
value and if the <output-mode>
value was previously set to "printable"
, it will be reverted back to "default"
(and this will happen every time we click the on Search
button).
@RequestScoped
@ManagedBean(name = "navigationBean")
public class NavigationBean {
@ManagedProperty(name = "printableBehaviorBean", value="#{printableBehaviorBean}")
private PrintableBehaviorBean printableBehaviorBean;
public void setPrintableBehaviorBean(PrintableBehaviorBean printableBehaviorBean) {
this.printableBehaviorBean = printableBehaviorBean;
}
public PrintableBehaviorBean getPrintableBehaviorBean() {
return printableBehaviorBean;
}
public String search() {
printableBehaviorBean.setOutputMode("default");
return "search";
}
}
And finally, the Search
button definition would be changed slightly to:
<af:button text="Search" action="#{navigationBean.search}" immediate="true" id="ab1" />
Now, another question of interest would be "Why removing immediate="true"
solves the problem?.
A UICommand
component decorated with immediate="true"
will make the framework skip the "Process validations", "Update model values" and "Invoke application" JSF life-cycle phases (i.e. the 3rd, 4th and the 5th phase). My assumption on your problem would be that before the "Invoke application" phase, the ADF implementation checks if the command components is decorated with a <af:showPrintablePageBehaviour>
component and if it is, then it programmatically changes the value of the <output-mode>
element. And since you have immediate="true"
on the "Search"
button, this value would be left as "printable"
. That's why when you go back to the form, it triggers a new tab.
So, in conclusion, either remove the immediate="true"
attribute, or follow the workaround with the beans I suggested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With