JSF execute javascript after f:ajax - javascript

In my JSF 2 web application, I use the following code to display and switch the contents of a rich:dataTable according to the selectedStatus:
<h:selectOneRadio id="statusSelection" value="#{backingBean.selectedStatus}" style="width:auto; float:left;">
<f:selectItem itemValue="AVAILABLE" itemLabel="Available" />
<f:selectItem itemValue="INACTIVE" itemLabel="Inactive" />
<f:ajax render="itemsDataTable" execute="#{backingBean.sortByTitel('ascending')}" />
<f:ajax render="itemsDataTable" event="click" />
</h:selectOneRadio>
The dataTable contains a4j:commandLink s, which unintentionally need to be double clicked in some IE versions after changing table content - I found out, that executing the following Javascript code (on IE's debugging console, after table contents have changed) solves the issue:
document.getElementById(<dataTableClientId>).focus()
My question is: How can I achieve automatic execution of the javascript code after the table contents have changed?

In order to execute JS code after the <f:ajax> is successfully completed, the following inline solution will do:
<f:ajax
render="itemsDataTable"
onevent="function(data) { if (data.status === 'success') {
// Put your JS code here.
document.getElementById('dataTableClientId').focus();
}}" />
Or the following external function solution (note: do not put parentheses in onevent, only the function name):
<f:ajax
render="itemsDataTable"
onevent="scriptFunctionName" />
function scriptFunctionName(data) {
if (data.status === 'success') {
// Put your JS code here.
document.getElementById('dataTableClientId').focus();
}
}
Also take a look at this answer: JSF and Jquery AJAX - How can I make them work together?
Also, double check the need of the event="click" in your f:ajax , because the default event in <h:selectOneRadio> is change which I think you better use... See also What values can I pass to the event attribute of the f:ajax tag?

Related

Access bean properties in f:ajax onevent function [duplicate]

In my JSF 2.0 (on JBoss AS 7) project, I would like on my ajax submitted forms to display a little icon status triggered on begin and complete phases, to let the end user know that something is still happening.
The primefaces p:ajaxStatus is not useful here, as I'd like to have many different icons at different places in my page.
I found a bit of the solution in this question: "How show different ajax status in same input?", but I still have a problem: in order to make my javascript function reusable, I need to provide an extra parameter to the call.
I did something like this:
<h:commandLink value="do something boy!">
<f:ajax render="#form" execute="#form" listener="#{myBean.doStuff}"
onevent="showProgress" />
<f:param name="extraParam" value="extraValue" />
</h:commandLink>
and I can see the parameter "extraParam" sent to the server through the request, but in my javascript showProgress method I cannot recover it through the only given parameter.
So my questions is: can I provide to my f:ajax onevent javascript method an additionnal parameter through f:param (or maybe f:attribute, or anything else)?
Wrap it in an anonymous function wherein you pass it as extra argument.
<h:commandLink value="do something boy!">
<f:ajax render="#form" execute="#form" listener="#{myBean.doStuff}"
onevent="function(data) { showProgress(data, 'extraValue') }" />
</h:commandLink>
with
function showProgress(data, extraParam) {
// Use "data" argument the usual way.
// The "extraParam" argument will contain "extraValue" in above example.
}

Transfer and trigger javascript code by ajax call with jsf

I have some jsf-code with a tag that is re-rendered by an ajax call. It contains something like
<h:outputScript>alert("Gotcha")</h:outputScript>
but this is only executed on first load, not on an ajax induced partial render.
This is but a minimal example, what I'm really trying to do is to trigger some server-generated javascript right after the ajax-call has returned, something like
<h:outputScript>#{scriptBean.getScript()}</h:outputScript>
I've seen calling .trigger("click") that is in javascript code returned from an ajax call, Asynchronize ajax calls and javascript code, how to run call some Javascript code with jQuery as soon as element loads to page by Ajax? and Running javascript code called by AJAX, but neither questions nor answers look like they address my question, least not without some additional hint or explanation.
And because I want to keep things small and simple, and because I could avoid anything above jsf:core (mostly), I'd prefer solutions that avoid using yafl (== yet another fancy library).
Edit: as for the comment from #BalusC I post more context:
<composite:implementation>
<h:form id="${cc.attrs.imgId}" styleClass="small" onchange="alert('Gotcha0');">
<f:event type="postAddToView" listener="#{mBean.register}" />
<f:event type="preRenderView" listener="#{mBean.init}" />
<f:attribute name="flav" value="#{cc.attrs.flav}" />
<h:graphicImage width="${cc.attrs.width}" id="${cc.attrs.imgId}"
onclick="if (event.isTrusted) this.nextSibling.value=mods(event);"
onmouseover="aa=this.id" alt="not found"
onchange="alert('Gotcha1');"
value="images/img?#{cc.attrs.flav}=#{mBean.getNextCount()}&imgId=#{cc.attrs.imgId}">
<f:ajax event="click" execute="#form"
onevent="function(data) { if (data.status === 'success') {
console.log('HiHo'+data.responseCode+'\n\n'+ data.responseText+'\n\n'+data.responseXML);
me=window.document.getElementById('#{cc.clientId}:#{cc.attrs.imgId}:#{cc.attrs.imgId}');
me.nextSibling.nextSibling.value=0;
me.nextSibling.value=0;
me.myfunc=function(event)
{
console.log('keyCode='+event.keyCode+' mods='+mods(event)+'/'+this.nextSibling.id);
this.nextSibling.value=mods(event);
this.nextSibling.nextSibling.value=String.fromCharCode(event.keyCode);
this.click();
}; }; }"
listener="#{mBean.handleEvent}" render="#this">
</f:ajax>
</h:graphicImage>
<h:inputHidden id="m" value="#{mBean.keyX}" />
<h:inputHidden id="k" value="#{mBean.key}" />
</h:form>
<h:outputScript>alert("Gotcha2")</h:outputScript>
<h:outputScript>var i=0;window.document.getElementById('#{cc.clientId}:#{cc.attrs.imgId}:#{cc.attrs.imgId}').myfunc=function(event)
{
aa='#{cc.clientId}:#{cc.attrs.imgId}:#{cc.attrs.imgId}';
this.nextSibling.value=mods(event);
this.nextSibling.nextSibling.value=String.fromCharCode(event.keyCode);
this.click();
};
</h:outputScript>
</composite:implementation>
"Gotcha2" shows up only at load time, once for each instance of the composite, but not when the component is re-rendered via ajax calls.
"Gotcha0" and "Gotcha1" are completely ignored.
The "HiHo" shows up for every ajax-call on the component, but I would like the function to fire only when the component is rendered, which is a subtle difference, because I might manipulate the render-list on server side, like
private void addToRenderMap(String obj) {
FacesContext context = FacesContext.getCurrentInstance();
Collection<String> renderIds = context.getPartialViewContext().getRenderIds();
renderIds.add(obj);
}
or even remove the calling component from the list.
(For example, for keypress "i", I want to only show image information in some other component and avoid unnecessary re-sending of the image data.)
Edit2: I see that onchange really is more a onvaluechange for fields that take input, so it's not a big surprise that this part of the code is ignored.

How to show a popup in primefaces with the requiredMessages, only if these messages exist?

I want to show a popup with the requiredMessages of some inputText fields when I click on a submit button. But just only in case of there are those messages. I have tried with bean variable and javascript on the oncomplete tag, but I'm not able to make it work properly. If I put visible="true" in p:dialog, the popup is always displayed, although I try to control it from the commandButton. Now, I have this, but the popup is never displayed:
<h:inputText id="Scheme"
required="true"
requiredMessage="Required.">
</h:inputText>
<h:commandButton id="submitModify" value="#{msg['systemdetail.modify']}"
action="#{sistem.modify}"
oncomplete="if (#{facesContext.maximumSeverity != null}) {dlg1.show();}">
</h:commandButton>
<p:dialog id="popup"
style="text-align:center"
widgetVar="dlg1"
modal="true">
<h:messages layout="table"/>
</p:dialog>
How can I do this? Thanks in advance.
Standard JSF and PrimeFaces does not support request based EL evaluation in on* attributes. RichFaces is the only who supports that. Besides, the standard JSF <h:commandButton> does not have an oncomplete attribute at all. You're probably confusing with PrimeFaces <p:commandButton>
There are several ways to achieve this:
Check the condition in the visible attribute of the <p:dialog> instead.
<p:dialog visible="#{not empty facesContext.messageList}">
or if you want to show validation messages only instead of all messages
<p:dialog visible="#{facesContext.validationFailed}">
Use PrimeFaces <p:commandButton> instead, the PrimeFaces JS API supports the #{facesContext.validationFailed} condition through the args object as well:
<p:commandButton ... oncomplete="if (args.validationFailed) dlg1.show()" />
If you need to check for what kind of messages, here is a way that I made work with primefaces. Since primefaces oncomplete is called after update, by updating the component holding the javascript function, the javascript function can be rebuilt using the latest #facesContext.maximumSeverity} values before executed.
<p:commandButton
oncomplete="executeAfterUpdate()"
update="updatedBeforeOnComplete"/>
<h:panelGroup id="updatedBeforeOnComplete">
<script language="JavaScript" type="text/javascript">
//
function executeAfterUpdate(){
if (#{facesContext.maximumSeverity==null
or facesContext.maximumSeverity.ordinal=='1'})
{
// your code to execute here
someDialog.show();
}
}
//
</script>
</h:panelGroup>

jsf ajax call: executing javascript function in the end

I'm working with JSF 2.0 and here's my form:
<h:form id="fff" onsubmit="reloadMap();">
<h:selectOneMenu value="#{rentCarPoolBean.state}">
<f:selectItems value="#{rentCarPoolBean.stateList}" id="stateList" />
<f:ajax event="change" render="cities stateSelected" onevent="showAlert"/>
</h:selectOneMenu>
<h:selectOneMenu id="cities" value="#{rentCarPoolBean.city}">
<f:selectItems value="#{rentCarPoolBean.cityList}"/>
</h:selectOneMenu>
<h:outputText value="#{rentCarPoolBean.state}" id="stateSelected" />
</h:form>
And the javascript function:
<script type="text/javascript">
function showAlert(data){
if (data.status == "complete")
alert(document.getElementById("stateSelected"));
}
</script>
What the above code does is on selecting a state from the first dropdown, it makes the ajax call and renders the 'cities' dropdown and the 'stateSelected' outputText.
Also, it calls the showAlert() javascript function.
What I want to do is call the javascript function after all the data is returned and both the dropdown and the outputText have been rendered.
But currently the javascript function is called before the elements are rendered and the alert displays null.
How do we make the javascript function execute in the end?
You need to hook on a status of success instead. This will run after the HTML DOM tree has been updated. The status of complete runs directly after the ajax response has been returned. This is admittedly a misleading status name, but you should try to interpret it in context of "HTTP request" like as the begin status.
Another problem is that the document.getElementById() selects items by the HTML element ID, not by JSF component ID. You need to give it exactly the ID as JSF has generated to the HTML. You can figure the right HTML element ID by viewing the page source in webbrowser.
All with all, your new function should look like this:
function showAlert(data){
if (data.status == "success")
alert(document.getElementById("fff:stateSelected"));
}
Here:
alert(document.getElementById("stateSelected"));
you're specifying only JSF component id, but you need to give a full clientId. Here's a link explaining this.

EL expression inside p:commandButton onclick does not update/re-render on ajax request?

The onclick attribute of my commandButton has some EL dependent Javascript inside. To be more specific, here is that piece of code:
<p:commandButton
onclick="javascript: if('#{userBean.user.friendList.size() gt 0}' == 'true') deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
value="Delete all friends?" />
deleteFriendsConfirmDialog clears the list of friends and updates the #form. The list of friends, commandButton and the dialogs are all in that form.
So I click the button, confirmation dialog comes up (because the length of friends' list is gt 0), I confirm and the list is emptied, the view is updated. However, when I click the Delete all friends? button once more, the confirmation dialog comes up again. Since the length of the list is now 0, I instead expect the error dialog to show.
That, I guess, is because the Javascript written inside onclick is not updated (although the button is in the form).
Edit: Changing #{userBean.user.friendList.size() gt 0} to #{not empty userBean.user.friendList} doesn't work neither.
How come? What's wrong here?
Any help appreciated. :)
Indeed. PrimeFaces (and standard JSF) does not re-evaluate the EL in on* attributes on a per-request basis. It only happens on a per-view basis. RichFaces however does that in <a4j:xxx> components.
You need to solve the problem differently. I suggest to use the visible attribute of the <p:dialog> instead.
<h:form>
...
<p:commandButton value="Delete all friends?" update=":deleteDialogs" />
</h:form>
...
<h:panelGroup id="deleteDialogs">
<p:dialog id="deleteFriendsConfirmDialog" visible="#{facesContext.postback and not empty userBean.user.friendList}">
...
</p:dialog>
<p:dialog id="friendsAlreadyDeletedErrorDialog" visible="#{facesContext.postback and empty userBean.user.friendList}">
...
</p:dialog>
</h:panelGroup>
An alternative is to use PrimeFaces' RequestContext in the bean's action method which allows you to execute JavaScript code programmatically in bean's action method (although this tight-couples the controller a bit too much with the view, IMO).
<p:commandButton value="Delete all friends?" action="#{userBean.deleteAllFriends}" />
with
RequestContext context = RequestContext.getCurrentInstance();
if (!user.getFriendList().isEmpty()) {
context.execute("deleteFriendsConfirmDialog.show()");
} else {
context.execute("friendsAlreadyDeletedErrorDialog.show()");
}
Unrelated to the concrete problem, your original onclick, while it does not work out in your particular case, shows some poor practices. The javascript: pseudoprotocol is superfluous. It's the default already. Remove it. Also the test against == 'true' is superfluous. Remove it. Just let the EL print true or false directly. The following is the proper syntax (again, this does not solve your problem, just for your information)
<p:commandButton
onclick="if (#{not empty userBean.user.friendList}) deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
value="Delete all friends?" />
It would have worked if you were using RichFaces' <a4j:commandButton>.
<a4j:commandButton
oncomplete="if (#{not empty userBean.user.friendList}) deleteFriendsConfirmDialog.show(); else friendsAlreadyDeletedErrorDialog.show();"
value="Delete all friends?" />

Categories