I want to move the JSF AJAX triggering code written with f:ajax, f:event and the h:commandLink (with its action attribute) to Javascript by using the jsf.util.ajax. - Why ? Because to avoid globally written handler functions to handle call backs. We are migrating the JS code to AMD Require JS and JSF isn't playing very well
Previously, the code to trigger AJAX calls from the view XHTML file in JSF was written like this :
<h:commandLink id="elemID" tabindex="-1" rendered="#{something.isEnabled ('showSomeLink')}">
<f:ajax render="#{someBean.getElemId('LinkID')}" onevent="renderAjax" />
<jsft:event type="ajax"> someBean.someMethod(); </jsft:event>
</h:commandLink>
The above markup gets rendered in HTML as follows:
Then, a click event was triggered on this link to execute the AJAX and the action.
The jsft:event was used which behaves similarly to its counterpart f:event.
I do not want to use this because it forces to define JS functions globally. In this case, renderAjax() in the onevent attribute of f:ajax
As you can see, This relies on a globally defined function called renderAjax() as the callback function to execute something and render on the UI side.
The trouble is we are moving into AMD and require JS and we have no scope of defining any globals in our code (we can but we do not want to). Even if we did, this ajax call gets triggered much before Require AMD loads
So I attempted to re-write this ajax call from the client side in JS, inside an AMD module, like this (from the generated HTML snippet's onclick mentioned above)
(Point to note, I did not know how to mention the action attribute in this JS code.)
jsf.util.chain(document.getElementById('elemID'), event,'jsf.ajax.request(\'elemID\',event,{render:\'LinkID\',onevent:renderAjax,\'javax.faces.behavior.event\':\'action\'})');
Once I wrote the above code in JS, I removed the f:ajax (since the render and the onevent attributes came inside the JS code itself ) and the jsft:event from the view, in the XHTML file. Once I removed this, it began causing a continuous reload of the page, as an infinite loop. I had to stop the server and put back the code to its old state.
Next, I thought h:commandLink was the issue and decided to replace h:commandLink with a normally rendered anchor tag via the h:outputLink.
Unfortunately this doesn't have an action attribute. The point is, although the element is rendered,
jsf.util.chain(document.getElementById('elemID'), event,'jsf.ajax.request(\'elemID\',event,{render:\'LinkID\',onevent:renderAjax,\'javax.faces.behavior.event\':\'action\'})');
Since my code with h:outputLink has no action attribute, it doesnt execute the method in the managed Bean.
Suppose I included the h:commandLink, without the jsft:event and the f:ajax, then it causes an infinite page reload.
I even added the action attribute to the h:commandLink after removing the jsft:event and f:ajax . I made it work with the below update.
<h:commandLink id="elemID" tabindex="-1" rendered="#{something.isEnabled ('showSomeLink')}" action="#{someBean.someMethod()}">
<f:ajax />
</h:commandLink>
and then using the following in JS:
jsf.util.chain(document.getElementById('elemID'), event,'jsf.ajax.request(\'elemID\',event,{render:\'LinkID\',onevent:renderAjax,\'javax.faces.behavior.event\':\'action\'})');
So far it works. But the problem is my renderAjax is still globally defined. Now i move my JS function into a require AMD module. The function renderAjax is no longer globally available and I move the jsf ajax code also into my module and access it as:
jsf.util.chain(document.getElementById('elemID'), event,'jsf.ajax.request(\'elemID\',event,{render:\'LinkID\',onevent:_t.renderAjax,\'javax.faces.behavior.event\':\'action\'})');
Note, _t.renderAjax() is now inside a module in Require JS. The Error i get now is _t is undefined. I guess it expects to see only global functions. The fun part is it automatically creates a wrapper function around the code. Is there any way to fix this?
(function(event
/**/) {
jsf.ajax.request('elemID',event,{render:'LinkID',onevent:_t.renderAjax,'javax.faces.behavior.event':'action'})
})
If someone could help me fix this, it would be extremely helpful.
Ok. I figured this out. I'm not sure if this is the right method. But it works.
Remove the following section as its not right to create a dummy link just for the sake of triggering a click event on it (in order to make JSF ajax work). It also forces to define global handler call backs as mentioned above which pollutes the global namespace, prevents the modularization of JS code, makes it imposs to move to AMD:
<h:commandLink id="elemID" tabindex="-1" rendered="#{something.isEnabled ('showSomeLink')}">
<f:ajax render="#{someBean.getElemId('LinkID')}" onevent="renderAjax" />
<jsft:event type="ajax"> someBean.someMethod(); </jsft:event>
</h:commandLink>
Now create a simple XHTML file called ajax.xhtml that serves as a template.
Create another file called needHelp.xhtml that uses the above file ajax.xhtml as the template
Both steps (1) and (2) have been shown in an image below:
http://i61.tinypic.com/2rgypsi.png
In the backing bean, do this:
http://i62.tinypic.com/1037bci.png
This completes the setup. Our Ajax response is now in the JSON format and written to the response stream.
Now, in the required AMD require Module,
define('checkChannel', ['jQuery', 'ajaxHandlers'], function($, ajaxHandlers){
(function checkChannel(){
$.ajax({
url : baseURL+"/needHelp.jsf",
dataType : "json",
type: "POST",
success : ajaxHandlers.renderAjax
});
})();
})
The success handler is used to update whatever DOM element needed, based on the response flags. In this case, it would update the element with id="LinkID", as defined in the original code snippet.
Now, the renderAjax is well wrapped inside an AMD module and is no longer required to be defined globally. Now there is no need to use the and or have dummy links created via to simulate a click and trigger AJAX in JSF. If the view state needs to be maintained, it can always be got and updated in a similar manner.
Also, baseURL is the basehref of your app. For example, if the page
was www.example.com/tool/index.jsf, then the baseUrl would be
www.example.com/tool/. So, the AJAX URL would be
www.example.com/tool/needHelp.jsf
PS: pardon the external image links as stackoverflow did not let me
post pics / more links as i needed atleast 10 reputation to post. I
had to use external images as I had some trouble formatting the code.
I have a custom javascript Ajax call in my jsf page. I capture and process the query string of the XMLHttpRequest in a filter. The filter adds a record to a table in the model.
Now I want the jsf page, without full page refresh, to reflect the updated model in one of the components (a Primefaces data table).
I guess what I need is a custom xmlHttpResponse...
Can anyone tell me how to do this? I'm scared it might be complicated, but I have no choice but to use the custom javascript...
The PrimeFaces <p:remoteCommand> is designed for this purpose.
Here's a basic kickoff example for your particular case:
<h:form>
<p:remoteCommand name="updateTable" action="#{bean.updateTable}"
process="#this" update="table" />
...
<p:dataTable id="table">...</p:dataTable>
</h:form>
It generates a JS function updateTable() which will invoke the #{bean.updateTable} method and update the component with (relative) client ID table. You just have to call the function updateTable() in JavaScript context.
updateTable();
You can even pass request parameters if necessary, it has to be sent as JS object:
updateTable({ name1: "value1", name2: "value2 });
No need to fiddle with homebrewed ajax requests and keeping the JSF state in sync.
I am using RichFaces 4. I am using flot as a JQuery Charting library and i want to implement a chart, that keeps refreshing itself via AJAX.
I get the data for the chart via JSON from my backing bean.
I am lost on how to get new data from a backing bean into a javascript variable. From what i understand i can't use <f:ajax> since there is no user interaction and no use of html input elements.
I think the solution would be the use of jsf.ajax.request. But i don't understand how to call that without an input-element either.
Following is a code snipped of how it should look like, but i don't know how to get the value from my backing bean into a javascript variable.
$(function() {
function update(){
//**dont know how this call should look like**
jsf.ajax.request('dev-form-input1', {render:'dev-form-output1'});
//'newAjaxData' would be the value from #{someBean.chartData}
plot.setData(newAjaxData);
// draw the chart with the new data
plot.draw();
//get an update every second
setTimeout(update, 1000);
}
I managed to send AJAX requests with jsf.ajax.request when using some input-element, but i didnt get the new value to render. And even if i could i wouldnt know hot to get it in a javascript variable (i dont have a lot of experience with javascript).
<h:form id="dev-form">
<h:inputText id="input1" value="#{someBean.chartData}"/>
<h:outputText id="output1" value="#{someBean.chartData}" />
</h:form>
note: i changed the javax.faces.SEPARATOR_CHAR to "-", because i need ":" for jquery.
Thanks for your help!
JSF is the wrong tool for the job. Use a webservice framework like JAX-RS, not a MVC framework like JSF. Then you can in the client end just use jQuery the usual way and so on.
See also:
Jersey (JAX-RS reference implementation) tutorial
Servlet vs RESTful
I have view which takes care of all the Ajax submits from the client side. And to differentiate them by I uses different submit button names such as this one
<input type="submit" value="Send" name="send_message">
Suggested from this question.
The only problem is that from the view side it doesn't seems to carry the name to the server side so I cannot use the following if-statement
if 'send_message' in request.POST:
It works if I send it normally with page fresh. But I want to use it with Ajax.
I came up with a hack that you can add this name with jQuery. Simply by after serializing() your data you then concatenate the name attribute by data += "&send_message"
Then the if statement will work. But it doesn't seems so clean. So I wonder if there's a better way to handle this? Or should I make different views to handle the different Ajax calls I have?
You really should post each form to a different URL.
If not, you could add a hidden input with the name of the form as the value.
<input name="form_name" type="hidden" value="form_1" />
views.py:
form_name = request.POST['form_name']
I have an issue with my portlet and I don't know exactly how to solve it.
My portlet adds or retrieves info from liferay's DB by inserting a name in 2 text fields.
After pressing the submit button, I see the response from the server, a JSON response like this:
{"id":301,"name":"Pepo"}
If a user correctly inserted or if the search throws a good result. I have to go back in the browser to see the portal again.
How can I use AJAX to pass the following URL dynamically from the portlet to the server without refreshing the page afterwards?
http://localhost:8080/c/portal/json_service?serviceClassName=com.liferay.test.service.TrabajadorServiceUtil&serviceMethodName=findByName&servletContextName=TrabajadorPlugin-portlet&serviceParameters=[param1]¶m1=NameInsertedByUser
Now I'm using the <form> tag like this:
<%
//Shows "New Employee" in the text field when portlet is rendered, or gets the user input and pass it as a param to the URL
PortletPreferences prefs = renderRequest.getPreferences();
String employee = (String)prefs.getValue("name", "New Employee");
%>
<form id="postForm" method="post" action="http://localhost:8080/c/portal/json_service">
<input name="serviceClassName" type="hidden" value="com.liferay.test.service.TrabajadorServiceUtil" />
<input name="serviceMethodName" type="hidden" value="create" />
<input name="servletContextName" type="hidden" value="TrabajadorPlugin-portlet" />
<input name="serviceParameters" type="hidden" value="[param]" />
<input name="param" type="text" value="<%=employee%>" />
<input type="submit" value="Submit"/>
</form>
I understand how AJAX works, but I need some help to create my function in order to achieve the URL to be correctly sent to the server for both GET and POST requests. This is my first try with AJAX.
Thank you very much, hope somebody understands my problem and could help me.
First of all, I see no point at all to use JSON services here. Just write ordinary portlet with MVC Controller, and in controller write action handling for corresponding actions (storing data, searching etc).
In controller you can directly call static methods like create or findByName from java class com.liferay.test.service.TrabajadorServiceUtil (or TrabajadorLocalServiceUtil) - that's how people usually do it.
If for some reason you really must use JSON, you should of course do these actions with AJAX calls - and render results using JavaScript.
Updating after question update:
The easiest and most correct way to send AJAX requests in Liferay would be to use AlloyUI JS framework that's a part of Liferay. You can read more on how to send AJAX requests with it here: http://www.liferay.com/web/nathan.cavanaugh/blog/-/blogs/4733559
In order to accomplish your goal I'd suggest implementing processAction(ActionRequest actRequest, ActionResponse actResponse) method in your controller/portlet.
In order to actually send data to it you'll have to have actionURL, which you can create using for example portlet:actionURL tag:
<portlet:actionURL /> or with Java code PortletURL actionUrl = portletResponse.createActionURL();
Then just submit your form using POST to this URL, and in actionRequest you'll have your parameters.