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.
Related
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.
}
i have a String var in class
String message;
private int checkConstraints()
int a = 0;
if (docProcessId==0) {
a++;
message = "<script language=\"javascript\"> alert('Please Select Doc Process Name'); </script>";
}else if (refTypeName.equals("")) {
a++;
message = "<script> alert('Enter Reference Type Name!');</script>";
}
return a;
}
actually i am doing like this but when this method is called not equals to 0 then message equals to whole the string print on page not giving alert any solution please
JSF by default HTML-escapes all model values as part of XSS attack prevention. Your concrete problem suggests that you had no idea of that. You can "solve" it by using <h:outputText> with escape attribute set to false.
<h:outputText value="#{bean.message}" escape="false" />
However, your concrete problem is bigger. You're in JSF/MVC perspective basically making two major design mistakes here:
Writing HTML code in model instead of in the view.
Performing validation in an action method instead of in a validator.
You should be writing HTML code in the view, not in the model. You should be performing validation using a normal JSF validator. JSF has a lot of builtin validators.
Besides, not really a design mistake, but more an user experience mistake, there's a third mistake: using JavaScript alerts to show validation messages. This is simply too 1990 and Web 1.0. We're currently in 2013 and have learnt a lot, a lot of the user experience failures made back then. Using JavaScript alerts to show validation messages is one of them.
Here's the right approach using JSF-provided validation facilities:
<h:form>
<h:selectOneMenu value="#{bean.docProcessId}" required="true"
requiredMessage="Please Select Doc Process Name">
<f:selectItems ... />
</h:selectOneMenu>
<h:inputText value="#{bean.refTypeName}" required="true"
requiredMessage="Enter Reference Type Name" />
<h:commandButton value="submit" />
<h:messages />
</h:form>
That's it. The required="true" tells JSF that those inputs are required. The requiredMessage attribute allows you to specify custom messages for required validation. The messages will be displayed in place as declared by <h:messages>. You can customize the layout by layout attribute and by CSS means like infoClass, errorClass, etc. You can even manually loop over it and manually create annoying alerts for each message instead of using <h:messages>:
<ui:repeat value="#{facesContext.messageList}" var="message">
<script>alert("#{message.summary}");</script>
</ui:repeat>
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?
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>
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.