RichFaces r:tabPanel - ajax

I got a TabPanel with 3 r:tabs nested in a collapsiblePanel
The r:tabPanel and r:collapsiblePanel are both switchType="ajax"
ajax
AJAX form submission is performed around the tabPanel, content of the
called tabPanel is uploaded on Ajax request. Only one at a time
tabPanel is uploaded on the client.
Each panel has some criteria the client can enter,
let's have the fictive scenario:
Tab 1:
Date = 01.01.2000
Tab 2:
Size >= 200MB
Tab 3:
Archived Yes/No (Checkbox)
when I am on Tab 1, and submit the form, everything works fine, and I get the proper search results.
However if I try to submit(searchButton) while Tab 2 is active, nothing happens.
Is there any documentation, where this may bug?
Code Snippet:
<h:panelGrid>
<!-- search panel -->
<r:collapsiblePanel id="searchPanel" header="Suche"
toggleListener="#{meldungListBacking.toggleSearchPanel}"
switchType="ajax" immediate="true"
expanded="#{meldungListBacking.searchPanelOpened}">
<r:tabPanel selectedTab="criteria" switchType="ajax">
<r:tab id="criteria"
header="#{res.meldungList_search_tab_criteria_label}"
styleClass="textlenght">...
</r:tab>
<r:tab id="othercriteria"
header="#{res.meldungList_search_tab_criteria_label}"
styleClass="textlenght">...
</r:tab>
<r:tab id="evenothercriteria"
header="#{res.meldungList_search_tab_criteria_label}"
styleClass="textlenght">...
</r:tab>
</r:tabPanel>
<h:panelGrid columns="2">
<h:commandButton id="searchButton" value="Suchen"
action="#{uebergreifendeLeistungswertListController.search}">
</h:commandButton>
<h:commandButton id="resetButton"
value="#{res.global_button_Ruecksetzen}"
action="#{uebergreifendeLeistungswertListController.reset}" />
</h:panelGrid>
</h:panelGrid>

Related

Issue with cell editor, Command button action fires even after internal validation error

For a column having a cell editor which has decimal as value, if i tried to enter string characters it showing validation error but it also invokes the action related to that button.
the save button code I have is
<p:commandButton id="saveBtn" value="#{msgs['button.save']}" accesskey="#{msgs['accesskey.save']}" escape="false" process="configRulePanel"
onclick="var d=PF('wigVardataTable'), c=d.jq.find('td:has(.ui-cell-editor-input:visible)'); if(c.length)d.saveCell(c); " update="myErrorMessages" action="#{ConfigBean.requestSave}" />
and the Input text in the cellEdit is
<p:inputText id="itemId" value="#{configRule.configItemValue}" validatorMessage="validation failed" validator="cellValidator" > <f:convertNumber minFractionDigits="0" maxFractionDigits="5"/> </p:inputText>
Iam using primefaces 5.3,
How to stop save action when there is error in the page , Any suggestions??

PrimeFaces Ajax Navigation with Browser History/Hashtag

I have implemented a web application which is a one-page-design. Which basically loads a single page then updates with AJAX the central content. The code is the following:
<h:body>
<pe:layout id="page" fullPage="true">
<!-- West -->
<pe:layoutPane id="west" position="west" >
<f:facet name="header">Main Menu</f:facet>
<h:form id="form1">
<p:panelMenu id="panelMenu">
<p:submenu label="Persons">
<p:menuitem value="Person List" update=":centerpanel"
actionListener="#{layout.setAll('formPersonList.xhtml', 'Person List')}">
</p:menuitem>
</p:submenu>
</p:panelMenu>
</h:form>
</pe:layoutPane>
<!-- Center -->
<pe:layoutPane id="content" position="center">
<h:panelGroup id="centerpanel" layout="block">
<ui:include id="include" src="#{layout.navigation}" />
</h:panelGroup>
</pe:layoutPane>
</pe:layout>
</h:body>
This basically works, but I want to enable browser navigation as well. For example like: http://ticketmonster-jdf.rhcloud.com/ with the hashtags on the url. So using the back/forward button I can go to the equivalent option.
Any idea how to do this?
I have created a blog post explaining how to get this to work using jQuery BBQ, based on your question.
With jQuery BBQ you can keep track of state, history and allow bookmarking while dynamically modifying the page via AJAX and/or DHTML.. just click the links, use your browser's back and next buttons, reload the page..
First we should include jQuery BBQ.
<h:outputScript library="js" name="jquery.ba-bbq.min.js" />
Now consider we have the menu (with all our nav rules)
<p:submenu label="Meat">
<p:menuitem outcome="/meat/steak.xhtml" value="Steak" />
<p:menuitem outcome="/meat/burger.xhtml" value="Burger" />
<p:menuitem outcome="/meat/chicken.xhtml" value="Chicken" />
<p:menuitem outcome="/meat/kebab.xhtml" value="Kebab" />
</p:submenu>
Then the centered content
<pe:layoutPane id="content" position="center">
<h:panelGroup id="centerpanel" layout="block">
<ui:include id="include" src="#{mainBean.currentNav}" />
</h:panelGroup>
</pe:layoutPane>
the include reflects the currentNav clicked.
now define a remoteCommand inside the form
<p:remoteCommand name="updateNav"
actionListener="#{mainBean.updateNav()}"
update=":centerpanel"/>
This remoteCommand will update our currentNav based on the hashtag.
Create your JS file or include the following code into the document ready
$(document).ready(function() {
$('.ui-menuitem-link').click(function(event) {
event.preventDefault();
var currentNav = $(this).attr('href').
substr($(this).attr('href').indexOf("/faces") + 6)
window.location.hash = '#' + currentNav;
})
$(window).bind('hashchange', function(e) {
var url = $.param.fragment();
updateNav([{name: 'currentNav', value: url}]); //remoteCommand Call
})
$(window).trigger('hashchange');
});
Basically first we handle our clicks on the menu items, setting the hash of the window.
then we define an event of the hashchange of the window, using the help of jQuery BBQ.
ManagedBean
public void updateNav() {
FacesContext context = FacesContext.getCurrentInstance();
Map map = context.getExternalContext().getRequestParameterMap();
currentNav = (String) map.get("currentNav");
}
For a complete code, please see my newly post created for the question.
Primefaces Hash Navigation Using jQuery BBQ
And also the example is available on github.
Hope it helps.
If I understand well your question, you want to navigate with back/forward button. You can do this with LinkedList in your backing bean:
private LinkedList<String> historyForBackPage= new LinkedList<String>();
public void setLastBackPage(String navigationCase) {
historyForBackPage.push(navigationCase);
if (historyForBackPage.size() > yourMaxSize) {
historyForBackPage.pollLast();
}
}
public String getLastBackPage() {
return historyForBackPage.pop();
}
and always add last page when you call layout.setAll method. The simple commandButton call getLastBackPage() method. Before try it, please configure navigation case in faces-config.xml.
If your case cannot work navigation case, because you work only one XHTML, than you could add back/foward page name for your bean and render your page. May be simple JavaScript call onclick="window.history.go(-1); return false;" it could be usefull in your case. I don't know. Please try it!
In my answer I focused only to back button, but I think you can adapt foward button in same way.
By the way, the Breadcrumb is nice PrimeFaces feature.
If you want to catch browser back clicking action, you can use one JavaScript or Ajax script.
For Ajax script please check this answer https://stackoverflow.com/a/10050826/1047582.

Is there a way to prevent JSF from displaying previous/outdated content in h:selectManyMenu after validation error?

I have a form with, say a text field and a multi-select field.
<h:form id="form2">
<h:messages for="text3" />
<h:inputText id="text3" value="#{danielBean.text3}" required="true"/>
<br/>
<h:messages for="select1" />
<h:selectManyMenu id="select1" value="#{danielBean.selStrings}"
style="height:8em;" required="true"/>
<f:selectItems value="#{danielBean.allStrings}" var="_item" itemLabel="#{_item} (length #{_item.length()})" />
<br/>
<p:commandButton
value="Submit"
action="#{danielBean.save()}"
update=":form2"
>
</h:form>
On submit, both get validated, and if validation is successful, the relevant variables in the backing bean are updated. Fair enough.
The problem happens when the validation (of the multi-select) is NOT successful. In my Bean, I have (particularly for the List<String>s allStrings and selStrings)...
#PostConstruct
public void init() {
text3 = "";
allStrings.clear();
allStrings.add("This");
allStrings.add("is");
allStrings.add("a");
allStrings.add("test");
selStrings.clear();
selStrings.add("a");
}
...so that the multi-select has one pre-selected option. If the user unselects that option (i.e. no options chosen), the validation will -of course- fail, an error message will be displayed...
...but the multiselect will not be empty. It will show the content from the bean, i.e. "a" selected. This is confusing to the user - getting an error message "input required", and being shown a filled-out field.
This appears to be a feature of JSF's lifecycle, see this article by BalusC:
"When JSF renders input components, then it will first test if the submitted value is not null and then display it, else if the local value is not null and then display it, else it will display the model value."
This works fine for the text field text3, because it submits as an empty string, not null.
The problem is that zero selected options from a multi-select means that the submitted value is null, that the local copy (I guess, since it's the first submit) is null, so that the model value ("a" selected) is displayed.
I do not want that.
How can I force JSF to use the null value it got submitted when rendering the validation response?
Thanks in advance
Antares42
There is no solution for this (other than reporting an issue to JSF guys and/or hacking in JSF source code). There's however a workaround: update only the components which really need to be updated on submit. Currently, you've set ajax to update the entire form. How about updating just the messages?
<h:messages id="text3_m" for="text3" />
...
<h:messages id="select1_m" for="select1" />
...
<p:commandButton ... update="text3_m select1_m" />
You can if necessary make use of PrimeFaces Selectors to minimize the boilerplate if you have rather a lot of fields:
<h:messages for="text3" styleClass="messages" />
...
<h:messages for="select1" styleClass="messages" />
...
<p:commandButton ... update="#(.messages)" />

JSF Ajax method does not persist variable in bean

I have two forms: one to define some filter settings (ajax) and with sumbit buttons which reloads the page by action="null" and one form with a single command button which executes the ajax listener "#{bean.activate}":
<h:form id="settingsForm">
<h:selectBooleanCheckbox value="#{bean.boolean1}" id="bool1">
<f:ajax event="click" render="#all" execute="bool1"/>
</h:selectBooleanCheckbox>
<ui:repeat var="step" value="#{bean.availableSteps}">
<h:commandLink action="#{bean.navigate(step)}">
<h:outputText value="#{step.name}" />
</h:commandLink>
</ui:repeat>
</h:form>
<h:form id="activateForm">
<h:commandButton value="set activate bool and rerender" >
<f:ajax event="click" execute="#form" render="#all" listener="#{bean.activate}"/>
</h:commandButton>
</h:form>
The problem is following:
when I change the checkbox (boolean in backing bean) and click the submit button in the same form, only the changes (in the backing bean) are persisted which were set in the same form.
When I execute the second form (bean.activate), it rerenders fine (shows some more information), but when I THEN submit the first form, the changes of the second form are lost (but they are working on the same bean). I want that it remembers also the variables set in the second form...
It seems that the values set by the other form are not persisted, because when i perform a form submit, all the "information" stored by ajax of the second form is lost.
e.g.
boolean boolean1 = false; //set by form 1
boolean show = false; //set by form 2 (ajax)
public void activate(Ajaxbehaviour...){ show = true; }
Should there be by default only ONE form at all? it seems that two forms (one big and one just so set a variable by ajax) are too much...

JSF AJax - How to render the output from an URL

I am trying to render the output of an URL in the same page, using JSF / Ajax (a4j) and so far I am having no luck. BTW, I am using RichFaces 4.0. For example, if the User clicks a row in a Table (or just a button), I like to show a web page right below the Table, that is relevant to the row clicked. Is there a way I can get the relevant URL using a Backing Bean and invoke that URL using A4J Tags? I searched for such tags or sample code and so far I could not find any.
Thanks for your help.
Embedding the result of an external URL in your webpage can only neatly be done with help of a HTML <iframe> element.
So, this should do:
<h:form>
<h:dataTable value="#{bean.websites}" var="website">
<h:column>#{website.name}</h:column>
<h:column>
<h:commandButton value="show" action="#{bean.setWebsite(website)}">
<f:ajax render=":website" />
</h:commandButton>
</h:column>
</h:dataTable>
</h:form>
<h:panelGroup id="website">
<iframe src="#{bean.website.url}"></iframe>
</h:panelGroup>
with
#ManagedBean
#ViewScoped
public class Bean {
private List<Website> websites; // +getter
private Website website; // +getter+setter
// ...
}

Resources