Change language with button on play framework - java

First sorry for my english...
I was searching for all internet but I can't find the answer of my question. I tried everything, looked in documentation, tutorials, videos, etc...
I put two buttons in the top of my page for the user can change the language, but I can't catch the value on my controller, I did everything but never can handle. I'm new on play :( please help...!!
I have this on my view:
<`form method="GET" action="#{Application.language("value")}"/`>
<`input> name="language" type="submit" value="en" title="#Messages("button.en")" </`>
<`input> name="language" type="submit" value="es" title="#Messages("button.es")" </`>
<`/form`>
And this on my controller:
public static void language(String idiom) {
String key = null;
key = idiom;
if(key.isEmpty()){
} else {
Lang.apply(idiom);
}
}
But when I try to catch the value on my controller always I received this message:
[RuntimeException: Unrecognized language: value]

Your HTML looks a little suspect, can you clean it up and repost along with your controller and route?
In the meanwhile, this is roughly what I'd expect to see to make sure your parameters get passed in properly:
Routes:
GET /language #controllers.LanguageController.index(language: String)
Controller:
LanguageController {
...
public Result index(String language) {
if(language != null && !language.isEmpty()){
Lang.apply(idiom);
}
... return
}
}
To make the setting stick in Play 2, see this post
playframework 2.2 java: how to set language (i18n) from subdomain

I did it a little modification with your comment below and this is how I have now.
Route:
POST / #controllers.LanguageController.changeLanguage(language: String)
View:
<form method="POST" action="changeLanguage("value")"/>
<input name="language" type="submit" value="en" title="English" </>
<input name="language" type="submit" value="es" title="Spanish" </>
</form>
Controller:
public class LanguageController extends Controller{
public Result changeLanguage(String language)
{
if(language != null && !language.isEmpty())
{
Lang.apply("en");
}
else
{
String idiom = language;
Lang.apply(idiom);
}
return ok(index.render(""));
}
Now I have this message error:
For request 'POST /changeLanguage(value)'
And the page error shows the route of the LanguageController this:
POST/#controllers.LanguageController#.changeLanguage(language:String)

You have messages.{lang} ( like messages.es or messages.en) in conf folder right?
And in application.conf valid langs should exist like;
application.langs="en,es"
If you have these so in any class which extends Controller you can run this method;
changeLang("es");
But in your case it seems that value of the idiom in your function is "value"
So if it's fine for you just replace the form header as;
<form method="GET" action="/language"/>
(assuming that /language will route to your method)
and replace the names of the html inputs as "idiom"
so you will be passing the right value of the input.

In play 2.8, Http.Context was deprecated which lead to changes in the interaction with the response object.
To change the language you need to do the following:
Inject an instance of MessagesApi into your controller
Create an instance of Lang object with the language you intend to use
Use method .withLang(Locale locale, MessagesApi messagesApi) on your result object
Code to illustrate:
private final MessagesApi messagesApi;
#Inject
public LoginController(MessagesApi messagesApi) {
this.messagesApi = messagesApi;
}
// ... now in the method invoked by the router
Lang lang = Lang.apply("en"); //english language
return ok().withLang(lang.toLocale(), messagesApi);
This changes the language throughout the rest of the session, since play will store the language in the cookie PLAY_SESSION. If you want to change only for one particular request, you must change the request object instead of the result object.
Reference here

Related

Liferay: AJAX call in configuration mode impossible?

Is it possible to use AJAX in configuration mode?
I am using custom class extending DefaultConfigurationAction to customize my portlet in the configuration mode. I override processAction and render methods, which work OK, but when I try to implement serveResource method, it is never called (returned status is 200 OK, but no data is fetched and no debug message is printed to the Liferay console).
My code for serveResource method:
public class TestConfigurationController extends DefaultConfigurationAction {
...
#Override
public void serveResource(PortletConfig portletConfig, ResourceRequest resourceRequest,
ResourceResponse resourceResponse) throws PortletException, IOException, Exception {
String resourceID = resourceRequest.getResourceID();
System.out.println("Resource id=" + resourceID
+ " in TestConfigurationController.serveResource()."); // this message never prints, method is not invoked
if (IMG_EDIT_ADD_NEW.equals(resourceID)) {
// more code
include(EDIT_NEW_IMAGE, context, resourceRequest, resourceResponse); // uses PortletRequestDispatcher, returns a JSPF fragment
} else {
super.serveResource(portletConfig, resourceRequest, resourceResponse);
}
}
}
I tried all options on the JS side, including both JQuery and AUI. Here is relevant code in configuration.jsp:
<portlet:resourceURL var="newImageJsp" id = "<%=IMG_EDIT_ADD_NEW%>">
</portlet:resourceURL>
<aui:button name="addNewImage" type="button" value="${addImage}"/>
<div id="<portlet:namespace/>newImageContainer">
<aui:field-wrapper name="newImageContainer" label="${addImage}">
</aui:field-wrapper>
</div>
<script type="text/javascript" charset="utf-8">
// Even this simple AUI AJAX call does not trigger serveResource method!
// AUI().ready('aui-base', 'aui-module', 'node', 'aui-io-request', function (A) {
// A.io.request('<%=newImageJsp.toString()%>');
// });
jQuery(document).ready(function () {
jQuery('#<portlet:namespace/>addNewImage').on('click', function (event) {
console.log('addNewImage clicked, url: ${newImageJsp}'); // returns correct url
jQuery.ajax({
dataType: 'text',
url: '${newImageJsp}',
success: function (data, status) {
console.log('returned resource: ' + data); // returns empty string
console.log('returned status: ' + status); // returns 200 OK, which is also in the Firebunetwork panel
$('#<portlet:namespace/>newImageContainer').html(data);
}
});
return false;
});
});
</script>
Debugging in console revealed, JS is working fine, function was called and returned status was 200 OK. However, returned data was empty and serveResource method on the server was never called.
As an experiment, I also tried to set
<aui:form action="${newImageJsp}" method="get" name="fm1">
which didn't call the serveResource method either, instead, it returned the view.jsp of the configured portlet.
And finally my configuration, which is exactly as in this working case:
portlet.xml:
<portlet>
<portlet-name>test-portlet</portlet-name>
<portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>
<init-param>
<name>contextConfigLocation</name>
<value>/WEB-INF/spring-context/portlet/test-portlet.xml</value>
</init-param>
<init-param>
<name>config-template</name>
<value>/WEB-INF/jsp/carousel/configuration.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode>
</supports>
<portlet-info>
<title>Test</title>
</portlet-info>
</portlet>
and liferay-portlet.xml:
<liferay-portlet-app>
<portlet>
<portlet-name>test-portlet</portlet-name>
<icon>/icon.png</icon>
<configuration-action-class>com.test.TestConfigurationController</configuration-action-class>
<requires-namespaced-parameters>false</requires-namespaced-parameters>
<ajaxable>true</ajaxable>
<header-portlet-css>/css/main.css</header-portlet-css>
<header-portlet-javascript>/js/jquery-1.11.3.min.js</header-portlet-javascript>
<header-portlet-javascript>/js/main.js</header-portlet-javascript>
</portlet>
</liferay-portlet-app>
So, it seems I have a similar problem, as this unresolved issue
I was thinking, that maybe it is the window state? Configuration mode always uses 'pop-up', but in all examples I only found AJAX calls using 'normal' window state. Maybe that is the problem? Is it even possible to make asynchronous JSPF loadings in pop-up mode? And even in configuration window? I never found a working example of use of AJAX in configuration mode and official Liferay only has examples for view mode.
Last but not least, I tested the same code in view.jsp for view mode and the resource serving method in TestViewController was called OK. I used Spring annotations here (#ResourceMapping). So the problem must be with Liferay and configuration mode. A bug maybe?
Thank you!
I did something similar and use the PrintWriter Object in resourceResponse:
PrintWriter writer = resourceResponse.getWriter();
writer.print([yourResult]);
http://liferayiseasy.blogspot.hk/2015/03/ajax-call-in-spring-mvc-portlet.html
You can also add a class extends MVCPortlet
Your previous view.jsp
<portlet:resourceURL var="newImageJsp" name="newImageResource"
</portlet:resourceURL>
...
// create a new class:
public class CustomResourceController extends MVCPortlet {
...
#Override(name="newImageResource") // <---- define the name attribute which match with view.jsp
public void serveResource(PortletConfig portletConfig, ResourceRequest resourceRequest,
ResourceResponse resourceResponse) throws PortletException, IOException, Exception {
String resourceID = resourceRequest.getResourceID();
System.out.println("Resource id=" + resourceID
+ " in TestConfigurationController.serveResource()."); // this message never prints, method is not invoked
if (IMG_EDIT_ADD_NEW.equals(resourceID)) {
// more code
include(EDIT_NEW_IMAGE, context, resourceRequest, resourceResponse); // uses PortletRequestDispatcher, returns a JSPF fragment
} else {
super.serveResource(portletConfig, resourceRequest, resourceResponse);
}
}
}
So, I tried both liferay-portlet:resourceURL portletConfiguration="true" and portlet:resourceURL, also with manual parsing and modifying the url before sending. The resource serving method (whether implementation of the serveResource, or completely new method using either Spring MVC or Liferay MVC (implementation class of MVCPortlet)), none worked in configuration mode. Seems like a bug to me, as there is nowhere even a mention about this peculiarity in official documentation.
The solution for me was to avoid resource serving at all and instead choose action phase (p_p_lifecycle=1). It is completely doable in AJAX, just had to override processAction method in my DefaultConfigurationAction implementation class.
Hope this saves someone the countless hours I spent with it.

Spring MVC Checkbox Binding Issue

Problem: Checkboxes values are not being bound to my form, properly. The result is that all my boolean values are null (at least the ones not being bound), and the existing ones are not being updated with values changed by the user.
Details: I'm aware that checkboxes are not submitted to the server if they are not selected. However, I do see the values in the request when hooking up an Eclipse debugger. The data is populated using jQuery/Datatable, but the data is posted back to the server using a form submit.
Spring MVC Version: 3.2.8
I'm assuming its configuration, but I'm not seeing where I am wrong. Here is a small code snippet of what I'm doing in my controller.
#Controller
public class CheckboxController {
...
#RequestMapping(value = "saveCheckboxes*", method = RequestMethod.POST)
public String saveCheckboxes(#ModelAttribute(SESSION_FORM_KEY) CheckboxForm form, BindingResult result, ModelMap model) {
// VALIDATE HERE...
if ( !result.hasErrors() ) {
// SAVE
}
else {
// DON'T SAVE (alert user)
}
}
}
So Spring MVC is used to binding request inputs to my form. The form is defined below, which has a list of summary objects with a boolean property.
public class CheckboxForm {
private List<Summary> summaries;
...
}
public class Summary {
private boolean selected;
...
}
I use jQuery/Datatables to populate my online grid of data. The inputs are created dynamically using a callback within datatables.
var tableWidget = (function($) {
init = function() {
...
"aoColumnDefs": [
{ "aTargets": [0], "sName": "", "mData": "selected" "stype": "html", "sClass": "center", "mRender": renderCheckbox, "bSortable":false, "sWidth": "50px" }
...
};
renderCheckbox = function(source, type, row) {
var $name = 'checkboxForm.summaries['+row.index+'].selected';
return createCheckbox($name, source);
};
createCheckbox = function(name, checked) {
var $checked = (checked === true) ? ' checked="checked"' : '';
return '<input type="checkbox" name="'+name+'" value="true"'+$checked+'/><input type="hidden" name="_'+name+'" value="on"/>';
}
...
))(jQuery);
After all of this, I hooked up the debugger and traced it into the WebDataBinder. I found that it seems to throw and exception in the method:
public boolean isWritableProperty(String propertyName)
saying the property cannot be evaluated. This happens for each property returned. However, I can confirm that what is in the request is the very inputs that I am expecting.
First, unless you know why avoid relative URL in #RequestMapping methods. It is a common cause of errors.
Next, as you directly generate your checkboxes without all the bells and whistles that adds spring:checkbox, you wont't get automatic error messages, and could experience problems in getting last checkboxes values if they are unchecked, as they will not be transmitted by browser and Spring will never see them giving a shorter list (or even an empty list if all are unchecked).
That being said, your problem is that you use checkboxForm.summaries[index].selected where Spring would expect only summaries[index].selected. Remove checkboxFormand your controller should affect values to the #ModelAttribute CheckboxForm form.

Invoke Java Method When Button Is Clicked

I have an old JSP application for which I cannot use Jquery or Ajax.
I have the following code snippet
function func(val){
if(val=="true"){
<%
myBean.myMethod("ABC","DET",0);
%>
myfrm.submit();
}
}
and I am calling this from a button's onClick event.
What I would like to do is invoke my Java method only when button is clicked. If page is refreshed java method should not be invoked.
How can I achieve this?
This is not possible. The java code is only executed when you refresh/load the page. Once the page is rendered, only client-side code can be executed.
You could have the button post to x.jsp and then do a redirect y.jsp
Looks like you have called your method within the jsp lifecycle.
As the jsp is parsed your method will be executed.
The functionallity you want you will most likely have to create an event.
<input type="hidden" value="" id="executeThis" onclick="document.forms[0].submit();"/>
<button id="doWork" type="button" onclick="execTheClick('executeThis', 'methodName');"/>
function execTheClick(linkId, methodName)
{
var fireOnThis = document.getElementById(linkId);
fireOnThis.value = methodName;
if (document.createEvent)
{
var evObj = document.createEvent('MouseEvents');
evObj.initEvent( 'click', true, false );
fireOnThis.dispatchEvent(evObj);
}
else if (document.createEventObject)
{
var evObj = document.createEventObject();
fireOnThis.fireEvent('onclick',evObj);
}
}
Hope that helps

jsf. How to post backbean object from jsf form to javascript

I am using Primefaces/JSF in combination with pure javascript tools in order to implement an image viewer & annotator. Image viewer is built upon the OpenLayers framework.
When the user annotates (draws shapes) on the canvas, a JSON object is created and upon Save action passed to the back bean. Back bean retrieves the object (deserialized) and stores it in to a file.
Here is the relevant code:
OpenLayers javascript (image-viewer.js):
function initialiseMap(){'
...
map = new OpenLayers.Map(imageEditorID, options);
imageLayer = new OpenLayers.Layer.TMS(imgURL, "", {
...
});
map.addLayer(imageLayer);
var vlayer = new OpenLayers.Layer.Vector("Editable");
map.addLayer(vlayer);
//draw controls and shape tools
...
//then define save action
var save = new OpenLayers.Control.Button({
...
var GEOJSON_PARSER = new OpenLayers.Format.GeoJSON();
var vectorLayerAsJson = GEOJSON_PARSER.write(vlayer.features);
//and finally post to server layer with drawn shapes
sendJSONToServer([{name:'param', value:vectorLayerAsJson}]);
...
The above Image Viewer/Map tool, is loaded via an p:outputPanel component of primefaces and uses sendJSONToServer remoteCommand to get JSON layer:
<h:head>
<script src="#{facesContext.externalContext.requestContextPath}/js/image-viewer.js" />
...
<h:body>
<h:form id="imageEditor">
<p:fieldset legend="Viewer">
...
// inoutHidden does not have on* events? how am i going to post to image-viewer.js?
<h:inputHidden value="#{imageAnnotations.fetchJsonString()}" />
...
<p:outputPanel layout="block" styleClass="imageEditorImagePanel" />
<p:remoteCommand immediate="true" name="sendJSONToServer" action="#{imageAnnotations.actionOnString}" />
</p:fieldset>
....
Finally in the backbean the JSON object is fetched and stored in a file (implementation is raw):
#ManagedBean(name="imageAnnotations")
public class ImageAnnotations {
//actionOnString fetches and saves the JSON string - this is a raw impementation
public String actionOnString() {
//Do the job and get and save JSON string
}
public String fetchJsonString(){
//Do the job and get JSON string
return jsonString;
}
}
The question is How am i going to use a JSF or primefaces element to make available the imageAnnotations.fetchJsonString() value for fetching from within js?
Even I can't give all answers, for me the filling of your hiddenInput should be managed as following:
#ManagedBean(name="imageAnnotations")
public class ImageAnnotations {
private String jsonString;
public void anyMethodFillingOrInitializingTheJSONString() {
this.jsonString = resultOfYourWork();
}
public String getJsonString(){
return this.jsonString();
}
public void setJsonString(String item) {
this.jsonString = item;
}
}
When you reload this hidden input field, just be sure to trigger a javascript parsing the String and updating your client-side Model. This can be done via the on* - events you can connect with Primefaces buttons.
Guys, can anybody help with the other parts?

Problem changing language application

as I asked time ago in this question, I solved my problem using this method:
In loging.xhtm, for instance:
<f:view locale="#{languageDetails.locale}" >
<head>
.....
<f:loadBundle basename="messages.Messages" var="msg1"/>
.....
</h:form>
</body>
</f:view>
2.In java source code I also made some changes:
public class LanguageDetails {
private static String locale = Locale.getDefault().getDisplayLanguage();
public void setLocale(String locale1) {
this.locale = locale1;
}
public synchronized String getLocale() {
return locale;
}
public synchronized String changeLanguage() {
return "changed";
}
}
But now I'm trying to have the same option, not just in Login page, but in other pages.
Adding the same code in other pages, doesn't work, because function setLocale is not called. Any help?
Thanks in advance
I realized, it's really important to put
<f:view locale="#{languageDetails.locale}" >
....
</f:view>
Or in every single file, or just in top file. Later, put <h:selectOneMenu> where necessary, but having always in mind that you can not have all <h:form> , <a4j:form>... etc. you want, it makes things more complicated. I put this form tags just on top files, and now everything is ok.
Hope this could help somebody.

Categories

Resources