I'm trying to update a whole page in adf when you click on a link to go to the same page with new page parameters. If I open the link in a new tab, it works fine, but opening it in the same tab doesn't update.
I have a page that just displays the parameter value from the url, a link to the same page with a different parameter value, and an output text that displays the datetime. My taskflow starts by calling RetrieveDateTime() and then goes to refrestTest.jsff. The taskflow is a region on refresh.jsf page.
public class RefreshDC {
private String dateTime;
public RefreshDC() {
super();
}
public void RetrieveDateTime() {
System.out.println("DC RETRIEVEDATETIME");
RefreshFacade rf = new RefreshFacade();
this.dateTime = rf.getDate().getDatetime();
}
public void setDateTime(String dateTime) {
this.dateTime = dateTime;
}
public String getDateTime() {
return dateTime;
}
}
The page fragment:
//refreshTest.jsff
<?xml version='1.0' encoding='UTF-8'?>
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
<af:panelGroupLayout id="pgl1" layout="vertical">
<af:outputText value="#{param.id}" id="ot1"/>
<af:goLink text="RP PDTLS" id="gl1" destination="/faces/refresh.jsf?
id=1234567890"/>
<af:outputText value="DateTime: #{bindings.dateTime.inputValue}"
shortDesc="#{bindings.dateTime.hints.tooltip}" id="ot2"
partialTriggers="gl1"/>
</af:panelGroupLayout>
</ui:composition>
The page:
//refresh.jsf
<f:view xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
<af:document title="refresh.jsf" id="d1">
<af:form id="f1">
<af:region value="#{bindings.refresh1.regionModel}" id="r1"/>
</af:form>
</af:document>
</f:view>
As i said, if you open the goLink in a new tab, it will update the dateTime, however if you open it in the same tab, dateTime remains the same. (The param.id does update in both cases)
You can refresh the whole page programatically by replacing your golink by an adf button with an ActionListener calling the following java bean function :
public static void refreshPage() {
FacesContext fc = FacesContext.getCurrentInstance();
String refreshpage = fc.getViewRoot().getViewId();
ViewHandler ViewH = fc.getApplication().getViewHandler();
UIViewRoot UIV = ViewH.createView(fc, refreshpage);
UIV.setViewId(refreshpage);
fc.setViewRoot(UIV);
}
I managed to solve this using the taskflow. Basically, I made the button go to a new page with a region. This region has a taskflow that reads the url parameters and if it matches my conditions, links back to the original page with new parameters (toDocumentsPage). Otherwise, goes to a different page (searchResults).Taskflow to refresh the page
Related
I want to implement an i18n-support for a wicket 7 application.
Requirements:
Translations must be easily editable by the admin-user
Translations must take place without redeployment
My actual apporach is to hold the translations inside a DB. All translations will be cached. If a translation is changed by a Frontend-task the cache and the db will be updated.
So far so easy.
Actually I'm stuck in replacing the translations inside a page.
A working solution would be loading every translation during implementation. These translations would be set inside many of wicket-elements.
I don't like this approach, because it'll mess up the code (html + java) heavily.
I'll try to implement a replacement-mechanism in my actual approach. After the page is rendered, the mechanism is run through the whole page and is doing these jobs:
search for all placeholders
load the translation for the placeholder-keys(cache)
replace the placeholders with the translations
This should work for body and header (site's title)
Here is an example of a wicket-template
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${landingpage.site.title}</title>
</head>
<body>
<header wicket:id="headerPanel">header</header>
${welcome.message}
<footer wicket:id="footerPanel">footer</footer>
</body>
</html>
In this case ${landingpage.site.title} and ${welcome.message} should be recognized and replaced. As you can see it is directly definied inside the template, not in the java-code. And this is what I want to achieve.
I hope I made the requirements clear enough. If not, don't mind to comment. I'll update the question to make it more clear.
My approach is to implement a BasePage (extends Page) and overwrite the onAfterRender-Method
#Override
protected void onAfterRender() {
super.onAfterRender();
Response originalResponse = RequestCycle.get().getResponse();
String updatedResponse = replaceWithTranslations(originalResponse);
originalResponse.reset();
originalResponse.write(updatedResponse);
}
The method replaceWithTranslations is not yet implemented and returns a simple String actually. This method should convert the outputstream of the originalRepsonse to a String, searches for placeholders and replace them with the values of the db.
This approach seems to have 2 difficulties:
I'm not getting the response as String
I'm getting a WicketRuntimeException (Page.checkRendering in Page.java:666)
Any advice would be great!
OK, the problems seems to be a very simple one.
The trick or the luck is, here we have a BufferedWebResponse. A simple cast will do the trick:
#Override
protected void onAfterRender() {
super.onAfterRender();
BufferedWebResponse originalResponse = (BufferedWebResponse) RequestCycle.get().getResponse();
String translatedResponse = replaceWithTranslations(originalResponse);
originalResponse.reset();
originalResponse.write(translatedResponse);
}
private String replaceWithTranslations(BufferedWebResponse originalResponse) {
String untranslatedText = originalResponse.getText().toString();
String translatedText = doTheTranslation(untranslatedText);
return translatedText;
}
Inspired by #RobAu I gave the wicket's approach of i18n a chance. Here is with what I came up with:
The template:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><wicket:message key="landingpage.site.title">Site-Title</wicket:message></title>
</head>
<body>
<header wicket:id="headerPanel">header</header>
<wicket:message key="welcome.message">Welcome</wicket:message>
<footer wicket:id="footerPanel">footer</footer>
</body>
</html>
wicket:message for attributes:
<input type="text" placeholder="username" wicket:message="placeholder:login.username"/>
The IStringResourceLoader:
#org.springframework.stereotype.Component
public class I18NResourceLoader implements IStringResourceLoader {
#Autowired
private I18NCache i18nCache;
#Override
public String loadStringResource(final Class<?> clazz, final String key, final Locale locale, final String style, final String variation) {
return loadTranslation(key, locale);
}
#Override
public String loadStringResource(final Component component, final String key, final Locale locale, final String style, final String variation) {
return loadTranslation(key, locale);
}
private String loadTranslation(final String key, final Locale locale) {
final Optional<Translation> optional = i18nCache.get(key, locale);
if (!optional.isPresent()) {
return key;
}
return optional.get().getText();
}
}
Translation and I18NCache are self-implemented classes.
And finally the registration:
public abstract class BasePage extends WebPage {
#SpringBean
private I18NResourceLoader i18NResourceLoader;
public BasePage(){
addI18NResourceLoader();
...
}
private void addI18NResourceLoader() {
final List<IStringResourceLoader> resourceLoaders = Application.get().getResourceSettings().getStringResourceLoaders();
final boolean existsResourceLoader = resourceLoaders.stream()
.filter(p -> p instanceof I18NResourceLoader)
.collect(Collectors.counting()) > 0L;
if (!existsResourceLoader) {
resourceLoaders.add(i18NResourceLoader);
}
}
...
}
Pro's:
Wicket's approach
No mess with RegEx-Replacement-Handling
SPR
Con's
Template feels a little more messy
Actually, I have no informations about the performance of this approach.
I decided to keep the logic of adding the ResourceLoader in BasePage by 2 reasons.
BasePage is responsible for everything concering the page-representation (weak reason :-) )
I'm using DI. If I would add the logic in the WebApplication, I would have to manually inject the I18NResourceLoader or its dependencies.
I think you can extend IComponentResolver to replace the placeholders like WicketMessageResolver.
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?
One DropDownChoice list on my webapp takes very long time to create, because of getting options by some operations with LDAP connection and SQL connection. And because of that the whole page is loading much more than a couple of seconds - I'd say too much.
So what I want to achieve, is to use (best for me) the built-in Ajax functionality of Wicket to lazy load this dropdown, but I have some problems.
I know how to make regular DropDownChoice list, this simple example working great for me - link
I also know how to make lazy-loaded paragraph, from wicket-examples - link (Source Code -> LazyLoadingPage.html/LazyLoadingPage.java)
But putting it together throwing me exceptions and resulting Wicket's Internal error.
Here is how I try to do it:
in HTML:
<select wicket:id="lazy"></select>
in Java:
private String selected = "abc";
(...)
add(new AjaxLazyLoadPanel("lazy") {
#Override
public Component getLazyLoadComponent(String id) {
//simulating long time for simple list
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
return new DropDownChoice<String>(
id, new PropertyModel<String>(this,"selected"),
Arrays.asList("abc","def"));
}
});
}
And I'm getting Internal Error from Wicket, with that in logs:
ERROR Unexpected error occurred
Component [content] (path = [0:lazy:content]) must be applied to a tag of type [select], not: '<div wicket:id="content">' (line 0, column 0)
MarkupStream: [markup = jar:file:/C:/Program%20Files/Apache%20Software%20Foundation/Tomcat%207.0/webapps/devservices/WEB-INF/lib/wicket-extensions-1.5.7.jar!/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.html
, index = 0, current = ''
and stacktrace.
I would really appreciate some help, what I'm doing wrong, or maybe some better code examples.
Thanks to bert, I'm putting here full solution, in case someone will use it in the future.
We need to create our own panel, because AjaxLazyLoadPanel can only change one panel to another.
Example of MyPanel.html:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:panel>
<select wicket:id="project"></select>
</wicket:panel>
</body>
</html>
and MyPanel.java :
public class MyPanel extends Panel {
private String selected = <what you want>;
private List<String> projectList <what you want>;
public MyPanel(String id) {
super(id);
add(new DropDownChoice<String>(
"project", new PropertyModel<String>(this, "selected"), projectsList));
}
}
On your main page html simply add this:
<span wicket:id="lazy2"></span>
and in main page java file:
add(new AjaxLazyLoadPanel("lazy") {
#Override
public Component getLazyLoadComponent(String id) {
return new MyPanel(id);
}
});
Hope it will help someone else too :-)
I'm trying to rerender a second dropdown when i change the value in the first one.
But nothing happens when I click and change the value in the first drop down.
Have I missed any crucial part?
My xhtml:
<h:form>
<h:selectOneMenu value="#{adminBean.currentLeadCategory}" required="true" styleClass="formfield fpgeo" style="width:20em;margin-right:20px;">
<a4j:support event="onchange" action="#{adminBean.currentLeadCategoryChanged()}"
reRender="componentToReRender"/>
<s:selectItems value="#{leadCategories}" var="leadCategory" label="#{leadCategory.name}" noSelectionLabel="Choose Category"/>
<s:convertEntity/>
</h:selectOneMenu>
<a4j:outputPanel id="componentToReRenderWrapper">
<h:selectOneMenu id="componentToReRender" value="#{adminBean.currentCounty}"
styleClass="formfield fpgeo" style="width:20em;margin-right:20px;">
<s:selectItems value="#{adminBean.counties}" var="county" label="#{county.name}" noSelectionLabel="choose"/>
<s:convertEntity/>
</h:selectOneMenu>
<h:messages/>
</a4j:outputPanel>
</h:form>
My bean:
#AutoCreate
#Scope(ScopeType.CONVERSATION)
#Name("adminBean")
#MeasureCalls
#Restrict("#{s:hasRole('admin') or s:hasRole('sales')}")
public class AdminBean implements Serializable {
private LeadCategory currentLeadCategory;
private List<County> counties = new ArrayList<County>();
private County currentCounty;
#Factory(value = "leadCategories", autoCreate = true, scope = ScopeType.SESSION)
public List<LeadCategory> fetchLeadCategories() {
Query query = entityManager.createQuery("select l from LeadCategory l");
return query.getResultList();
}
public LeadCategory getCurrentLeadCategory() {
return currentLeadCategory;
}
public void setCurrentLeadCategory(LeadCategory currentLeadCategory) {
this.currentLeadCategory = currentLeadCategory;
}
public County getCurrentCounty() {
return currentCounty;
}
public void setCurrentCounty(County currentCounty) {
this.currentCounty = currentCounty;
}
public void currentLeadCategoryChanged() {
this.loadCountiesForCategory();
}
public List<County> getCounties() {
return counties;
}
public void setCounties(List<County> counties) {
this.counties = counties;
}
public void loadCountiesForCategory(){
if(currentLeadCategory == null){
counties = new ArrayList<County>();
}
counties = new ArrayList<County>(currentLeadCategory.getCounties());
}
}
EDIT 1:
If i check firebug i get an error:
Timestamp: 7/19/12 4:14:44 PM
Error: ReferenceError: A4J is not defined
Source File: http://localhost:8080/admin/admin.seam?cid=11
Line: 1
Ok found the problem! Major crazyness going on here. Someone has set LoadScriptStrategy
param to NONE in the web.xml. This makes that the framework.pack.js and ui.pack.js is NOT loading.
<context-param>
<param-name>org.richfaces.LoadScriptStrategy</param-name>
<param-value>NONE</param-value>
</context-param>
Found this page at docs.jboss
If you use the "NONE" strategy, you must include the following scripts
in your portlet or portal page header. If you are using JBoss Portal,
you can add this to the jboss-portlet.xml file.
Added <a4j:loadScript src="resource:///org/ajax4jsf/framework.pack.js"/>
to my header template and viola everything works like a charm.
I love my job =)
I can see clearly that your xhtml has an ending tag </a4j:outputPanel> but no starting tag: <a4j:outputPanel>
If you rearrange your tags it will work.
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.