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
// ...
}
Related
Working in JSF2 and ajax, i can't figure out what's the value of the $.ajax URL attribute in JSF context as i want to submit a form and update a div staying in the same page
Is it the following?
((HttpServletRequest) facesContext.getExternalContext().getRequest()).getContextPath()`
in my opinion you need pass value to the backing bean and set the parameter, after this you need to update this part (div).
see this http://www.mkyong.com/jsf2/4-ways-to-pass-parameter-from-jsf-page-to-backing-bean/
<p:commandButton action="#{bean.setId}" update="div">
<f:attribute name="id" value="12" />
</p:commandButton>
Another way is using flash, see this: https://javaserverfaces.java.net/nonav/docs/2.0/javadocs/javax/faces/context/Flash.html
lets say you have a form like this:
<div id="yourDivId">
<h:outputText value='#{yourControllerClass.yourAttribute}'></h:outputText>
</div>
<h:form>
<h:commandButton value="update">
<f:ajax execute="#form" listener="#{yourControllerClass.updateAttribute}"
render=":yourDiveId">
</f:ajax>
</h:commandButton>
</h:form>
in your ControllerClass/bean:
public final void updateAttribute(AjaxBehaviorEvent event){
// do what ever you want, get values, set another values, after that your Div will be auto updated
}
this way, you don't need to care about ajax params or URL...etc.
EDIT:
if you want to get a paramater from a request URL, then you can get it like this:
String paramVal = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get(key);
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 any way to include the page's title inside an f:ajax tag, so that its content is also updated at run time?
currently my f:ajax tag looks like this -
<f:ajax render="#form">
i tried to add an id to the h:head tag, and add that id to the 'render' property of the f:ajax tag, but if i do so i get an error when the page loads -
<f:ajax> contains an unknown id 'pageHead' - cannot locate it in the context of the component B1
cheers,
eRez
Interesting question. I think there is no such command in render of ajax (like #form) to re-render the page title. What you can do is to wrap <title> with <h:form> or other "grouping" component (eg. h:panelGroup as Daniel said) like this :
<h:form id="titleForm">
<title>#{fooBean.fooTitle}</title>
</h:form>
And then call ajax update eg. with button :
<h:commandButton immediate="true" value="Change title">
<f:ajax event="click" render=":titleForm" listener="#{fooBean.changeTitle}"/>
</h:commandButton>
Bean:
private String fooTitle;
public void changeTitle() {
this.fooTitle= "updatedTitle";
}
// getter/setter
I don't know what else could you do, this should work. So wrap your title with <h:form id="..."> and then render it from ajax.
I'm using JSF 2.0.4
There is a component under a form in which there is an f:ajax
<h:form id="formid"....>
......
<h:outputText id="textid" ........../>
.........
<h:commandLink id=".." value="...">
<f:ajax event="click" render="formid" execute="input" listener="#{bean.action}"/>
<h:commandLink/>
<h:form/>
Is there any expression for render attribute to exclude textid from formid so that the form is rendered but not the outputText after the ajax is fired?
I'm not aware of a way to specify "everything in the form except this", but instead of using the form id as the render keyword, you could just list off the child ids under the form you want rendered and not include the id of the outputText, i.e. something like
<f:ajax event="click" render="id1 id2 id3" execute="input" listener="#{bean.action"/>
I'm not sure why you want this though - if you don't want the output text to be updated when that ajax event fires, I would think all you would have to do is simply not update it in the listener?
Good Afternoon,
I have a search page that uses ajax to render a several datatables without refreshing the page.
It is mandatory for me to call a Method as a Listener for each table.
Below is the snippet for the first datatable that works fine.
To render a second datatable I need to call a method #{evalController.prepareList} as a Listener for the ajax. The problem is that <f:ajax "Listener" attribute won't take more than one method.
So the remaining way is to call <f:ajax several times, and each time with a different listener, which does not work. Is there a way to achieve this?
If not, should I create a method in the managed Bean that calls all the methods that I need and use it as the one listener?
Thanks in advance for your help.
<h:form id="searchform">
<h:panelGrid columns="3" >
<p:inputText value="#{ddnController.patientID}" id="pidinput" maxlength="7" size="7">
<f:ajax execute="#this" event="keyup" render="searchbutton ddntable" listener="#{ddnController.prepareList}"/>
</p:inputText>
<h:commandButton image="#{resource['images/search.png']}" id="searchbutton" value="#{bundle.Search}"
action="submit" actionListener="#{ddnController.prepareList}"
disabled="#{empty ddnController.patientID or ddnController.patientID.equals('0')}"/>
<p:panel><h:outputText value="Saisir 0 pour avoir tous les Patients" style="font-style: italic;"/></p:panel>
</h:panelGrid>
<p:dataTable id="ddntable" value="#{ddnController.items}" var="ddn" rendered="#{!empty ddnController.items}" paginator="true" >....
I am still not sure why the composite method do not have effect when called. Probably it is not called during before or after the right phase (I'll be profiling it later). Anyway, I found a solution with two edges (it is solving my problem but makes me sacrifice the use of ajax) :
So Instead of calling - from each managed bean - the method (prepareList()) which I use as listener:
private DataModel items = null; // Getter to retrieve items
// ......
public String prepareList() {
recreatemodel();
return "List";
}
private void recreatemodel(){
items=null;
}
(by the way, this method sets the datamodel to NULL to refresh it, and that is how my datatables get refreshed).
Inside the command button I nested property action listener:
<h:commandButton image="#{resource['images/search.png']}" id="searchbutton" value="#{bundle.Search}"
action="submit"
disabled="#{empty ddnController.patientID or ddnController.patientID.equals('0')}">
<f:PropertyActionListener target="#{ddnController.items}" value="#{null}" />
<f:PropertyActionListener target="#{evalController.items}" value="#{null}" />
<f:PropertyActionListener target="#{corController.items}" value="#{null}" />
<!--...etc -->
</h:commandButton>
I wish <f:PropertyActionListener /> could be nested inside <h:ajax/>.
If somebody has a solution that allows to use property action listener and ajax to avoid submitting the form with a button, s/he is welcome. I'll make then his/her answer as accepted.