How to display menu from database in a JSF template - jsf

I want to display menu in JSF template. Every user of my application has different menu and the menu is stored in database. Here is my code,
MenuBean.java
public List<Menuitem> getUserMenu() {
List<Menuitem> menuitems = (List<Menuitem>) em.createQuery("_____________").setParameter("_______", _______).getResultList();
return menuitems;
}
pageTemplate.xhtml
<div class="container">
<div id="navigation">
<ul>
<ui:repeat var="_item" value="#{menuitemBean.userMenu}">
<li><h:outputLink value="#{_item.url}">
<h:outputText value="#{_item.name}" />
</h:outputLink></li>
</ui:repeat>
</ul>
</div>
<div id="content">
<h1>
<ui:insert name="header" />
</h1>
<h2>
<ui:insert name="subheader" />
</h2>
<ui:insert name="main" />
</div>
</div>
Problem is each time I navigate to a new page (.xhtml file) which is using the same template (pageTemplate.xhtml) the menu is loading all over again.
How can I load the menu only once per user.

If the menu is dependent on the user, it would be better to create a bean with a scope session that will store the content of this menu.
This way, once the menu is initialized the first time, it will not be re-initialized. Your code will look like that:
public class MySessionBean ... {
private List<Menuitem> menuItems = null;
public List<Menuitem> getUserMenu() {
if (menuItems == null) {
// Initialize the menu items.
menuItems = ...;
}
return menuitems;
}
Note that you can also initialize the menuItems objects in the constructor, or in a post-construct method (i.e. a method called just after the bean is instantiated).
An important thing also : do not put database access code in your beans (your em.createQuery(...)). Move that on service / DAO layers, and let the bean call the service to retrieve the information needed to build the menu items.

You should NOT put logic accessing the database in a getter method, because they are often called more than once in the same request.
To load your menu once for each user, put the property in a #SessionScoped backing bean and then initialize it in a #PostConstruct annotated method:
#SessionScoped
public SomeBean {
private List<Menuitem> menuItems;
#PostConstruct
public void init() {
menuItems = (List<Menuitem>) em.createQuery("_____________")
.setParameter("_______", _______).getResultList();
}
// getter and setter for menuItems
}
As the bean is in the session scope, it will exist as one instance for each user session in your application.
Note that I assumed you are using JSF 2, because you tagged the question as java-ee-6.

Related

BootsFaces selectMultiMenu not rendering with ajax

i am using a selectMultiMenu from bootsFaces, the initial values are showed perfectly, but after rendered, with the new values the combo doesnt open, if I check the source code in my browser it shows that the bean loeaded the values correctly. It only happens with this bootsFaces's element, the rest of my project with jsf render with no problems with ajax.
Any clue? Thanks!
<h:form id="form-Principal">
<h:panelGroup id="panel-Principal" layout="block" >
<div class="col-md-12">
<div class="col-md-1">
<label for="servicio" class="control-label">Servicio:</label>
</div>
<div class="col-md-2">
<h:selectOneMenu disabled="#{empty testops.ambiente}" id="servicio" class="combobox form-control" value="#{testops.servicio}" >
<f:selectItem itemValue="" itemLabel="Seleccione..."/>
<f:selectItems value="#{testops.listServicios}" />
<f:ajax event="change" listener="#{testops.obtenerOperaciones}" render="cboperacion" execute="#this"></f:ajax>
</h:selectOneMenu>
<h:message for="servicio" class="error"/>
</div>
<div class="col-md-1">
<label for="operacion" class="control-label">Operación:</label>
</div>
<div class="col-md-2">
<b:selectMultiMenu id="cboperacion" value="#{testops.operacion}" nonSelectedText="Seleccione...">
<f:selectItems value="#{testops.operaciones}"/>
</b:selectMultiMenu>
</div>
<div class="col-md-1">
</div>
<div class="col-md-1">
<f:ajax render=":salida form-Principal:panel-Principal" execute="#form" onevent="loading">
<h:commandLink class="btn btn-danger boton_rojo pull-right" value="Ejecutar" action="#{testops.ejecutarOperaciones()}"></h:commandLink>
</f:ajax>
</div>
</div>
</h:panelGroup>
</h:form>enter code here
Onload:
After rendering, it has diffent values, but combo is not display.
I've tried to reproduce your bug without success. Or rather: the code works as intended. The <b:selectMultMenu> is updated with the new values.
[meta] I know this isn't an answer (yet)... I just chose the answer because it's the only way to include source code. [/meta]
So I suggest you
copy me example code below into your project and see if it works
or you send me a "reproducer", i.e. a tiny but complete project showing the problem. For instance, you could upload a Maven project to GitHub. Please reduce the reproduces as much as possible. For instance, I need to be able to run it without configuring a database.
Here's the sourcecode I used to reproduce your bug:
As a basis, I used our showcase.
I copied your JSF code snippet into the empty.xhtml.
I created a JSF bean as follows:
package de.beyondjava.jsf.sample.carshop;
import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
#ManagedBean
#SessionScoped
public class Testops {
private String ambiente = "que";
private List<String> listServicios = new ArrayList<>();
private String operacion;
private List<String> operaciones = new ArrayList<>();
private String servicio;
{
listServicios.add("Servicio 1");
listServicios.add("Servicio 2");
shuffleOperaciones();
}
public void ejecutarOperaciones(Object o) {
}
public String getAmbiente() {
return ambiente;
}
public List<String> getListServicios() {
return listServicios;
}
public String getOperacion() {
return operacion;
}
public List<String> getOperaciones() {
return operaciones;
}
public String getServicio() {
return servicio;
}
public void obtenerOperaciones(Object o) {
shuffleOperaciones();
}
public void setAmbiente(String ambiente) {
this.ambiente = ambiente;
}
public void setListServicios(List<String> listServicios) {
this.listServicios = listServicios;
}
public void setOperacion(String operacion) {
this.operacion = operacion;
}
public void setOperaciones(List<String> operaciones) {
this.operaciones = operaciones;
}
public void setServicio(String servicio) {
this.servicio = servicio;
}
private void shuffleOperaciones() {
operaciones = new ArrayList<>();
for (int i = 0; i < 4; i++) {
operaciones.add("opción " + Math.ceil(Math.random()*1000));
}
}
}
When I chose one of the options of the first combobox, the <b:selectMultiMenu> is updated with the new (random) values.

Radio buttons using twitter bootstrap - unable to get value

I've browsed SO, and found some answers that have guided me closer to getting working radio buttons, but I'm stuck now.
I have the buttons, but am unable to get the value of the selected one.
I'm using JSF, hence the #{searchFlightsBean.setDir()}
Here's what I currently have:
<h:panelGrid>
<div class="btn-group" data-toggle-name="is_private" data-toggle="buttons-radio" >
<button type="button" value="0" class="btn" data-toggle="button">Public</button>
<button type="button" value="1" class="btn" data-toggle="button">Private</button>
</div>
<h:inputHidden id="hiddenDir" value="0" valueChangeListener="#{searchFlightsBean.setDir()}" onchange="submit()"/>
</h:panelGrid>
<script>
$(function() {
$('div.btn-group[data-toggle-name]').each(function() {
var group = $(this);
var form = group.parents('form').eq(0);
var name = group.attr('data-toggle-name');
var hidden = $('input[name="' + name + '"]', form);
$('button', group).each(function() {
var button = $(this);
button.on('click', function() {
hidden.val($(this).val());
});
if (button.val() == hidden.val()) {
button.addClass('active');
#{searchFlightsBean.setDir(button.value)}
}
});
});
});
</script>
In my bean, when setDir() is called, I am logging the value that it receives, like so:
public void setDir(ValueChangeEvent e) {
this.dir = e.getNewValue().toString();
log.info("NEW DIRECTION: " + this.getDir());
}
It doesn't log - setDir() is never called. For some reason the valueChangeListener attribute on the h:inputHidden tag doesn't work. Am I missing something?
Your concrete problem is caused because you used valueChangeListener the wrong way.
<h:inputHidden ... valueChangeListener="#{searchFlightsBean.setDir()}">
This does not match the method signature. You should omit the parentheses ().
<h:inputHidden ... valueChangeListener="#{searchFlightsBean.setDir}">
Otherwise JSF expects an argumentless setDir() method. Then, you're nowhere in JavaScript triggering the change event on the input element. The onchange="submit()" is therefore never invoked. You should be doing hidden.trigger("change") in JS to achieve that.
But, after all, this is somewhat clumsy. You're sending a full synchronous request and your JS code is rather overcomplicated (and stops working once you ajax-update the form). Provided that you're indeeed using JSF 2.x, I suggest to bring in <f:ajax> — which unfortunately doesn't work in <h:inputHidden>, hence the <h:inputText style="display:none"> — and to make use of $.on() in jQuery to keep the functions working even when you ajax-update the DOM.
<h:form>
<div class="btn-group" data-toggle-name="is_private" data-toggle="buttons-radio" >
<button type="button" value="0" class="btn" data-toggle="button">Public</button>
<button type="button" value="1" class="btn" data-toggle="button">Private</button>
</div>
<h:inputText id="is_private" value="#{bean.dir}" style="display: none;">
<f:ajax listener="#{bean.changeDir}" />
</h:inputText>
<!-- Note: <h:inputText id> must be exactly the same as <div data-toggle-name> -->
</h:form>
<h:outputScript>
$(document).on("click", "[data-toggle=buttons-radio] button", function() {
var $button = $(this);
var id = $button.closest(".btn-group").attr("data-toggle-name");
var $input = $button.closest("form").find("input[id$=':" + id + "']");
if ($input.val() != $button.val()) {
$input.val($button.val()).trigger("change");
}
});
</h:outputScript>
(noted should be that the whole script should really be placed in its own .js file which you include by <h:outputScript name="some.js" target="body">; note that you don't need $(document).ready() nor $(function() {}) mess; also note that the very JS function is reusable on all other <div data-toggle="buttons-radio"> groups without changes)
With this bean:
private Integer dir;
public void changeDir() {
System.out.println("New direction: " + dir);
}
// ...
(noted should be that when you're doing further nothing relevant in changeDir() method, then you could just omit the whole method and <f:ajax> altogether and revert <h:inputText style="display:none"> back to <h:inputHidden> and remove .trigger("change") and rely on the regular form submit. It'll work as good)
You cannot just call any backing bean functions via Expression Language calls (#{...}) in JavaScript.
What you could do, is using a4j:jsFunction to offer your bean method to the java script code. That might look like this:
<a4j:jsFunction name="setDir" action="#{searchFlightsBean.setDir()}" ajaxSingle="true">
<a4j:param name="dir" assignTo="#{searchFlightsBean.dir}" />
</a4j:jsFunction>
See http://docs.jboss.org/richfaces/latest_3_3_X/en/devguide/html/a4j_jsFunction.html
and http://showcase.richfaces.org/richfaces/component-sample.jsf?demo=jsFunction&skin=blueSky

How to render a custom attribute of <h:outputLink>?

I am trying to implement pinterest's pinit button using a snippet like the one below:
<h:outputLink value="http://pinterest.com/pin/create/button/" class="pin-it-button" count-layout="horizontal">
<f:param name="url" value="#{beanOne.someMethod}/sometext{prettyContext.requestURL.toURL()}"/>
<f:param name="media" value="#{beanOne.someOtherMethod}/sometext/somemoretext/#{beanTwo.someMethodTwo}-some-text.jpg"/>
<f:param name="description" value="#{beanTwo.someOtherMethodTwo}"/>
<img border="0" src="//assets.pinterest.com/images/PinExt.png" title="Pin It" />
</h:outputLink>
Here are the gotcha's:
the whole markup is created from the combination of four different methods from two different beans as well as some static text
the url parameters obviously need to be urlencoded, therefore I am using f:param inside h:outputLink so that they get urlencoded
the generated a tag needs to have the non-standard count-layout="horizontal" attribute
Now my question is either one of:
How can I inject the count-layout attribute into h:outputLink or the generated anchor tag
Otherwise if I cannot, what would be another non-invasive (I don't want to change the bean methods) way to accomplish the required pinit button markup?
The required markup can be found at http://pinterest.com/about/goodies/ down in the "pin it button for websites" section.
Either use a normal <a> element along with a custom EL function which delegates to URLEncoder#encode().
<c:set var="url" value="#{beanOne.someMethod}/sometext#{prettyContext.requestURL.toURL()}"/>
<c:set var="media" value="#{beanOne.someOtherMethod}/sometext/somemoretext/#{beanTwo.someMethodTwo}-some-text.jpg"/>
<c:set var="description" value="#{beanTwo.someOtherMethodTwo}"/>
<a href="http://pinterest.com/pin/create/button/?url=#{utils:encodeURL(url)}&media=#{utils:encodeURL(media)}&description=#{utils:encodeURL(description)}" class="pin-it-button" count-layout="horizontal">
<img border="0" src="//assets.pinterest.com/images/PinExt.png" title="Pin It" />
</a>
(note that the class attribute was invalid for <h:outputLink>, you should be using styleClass)
Or create a custom renderer for <h:outputLink> which adds support for count-layout attribute. Assuming that you're using Mojarra, simplest would be to extend its OutputLinkRenderer:
public class ExtendedLinkRenderer extends OutputLinkRenderer {
#Override
protected void writeCommonLinkAttributes(ResponseWriter writer, UIComponent component) throws IOException {
super.writeCommonLinkAttributes(writer, component);
writer.writeAttribute("count-layout", component.getAttributes().get("count-layout"), null);
}
}
To get it to run, register it as follows in faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>javax.faces.Link</renderer-type>
<renderer-class>com.example.ExtendedLinkRenderer</renderer-class>
</renderer>
</render-kit>

Using CKEditor instead of PrimeFaces Editor

I am trying to use CKEditor in my JSF application. How to get the content of CKEditor into backing bean..?
index.xhtml
<form action="" method="post">
<p>
My Editor:<br />
<textarea cols="90" rows="20" id="editor1" name="editor1" value="#{EditorBean.value}"></textarea>
<script type="text/javascript">
CKEDITOR.replace( 'editor1',
{
uiColor: '#85B5D9'
});
</script>
<input type="button" value="Clear" name="clear" onclick="clear1()"/>
</p>
</form>
BackingBean
#ManagedBean
public class EditorBean {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
System.out.println("Content: "+value);
}
}
When I tried to print the value, It is not printing. Help me on this issue. PrimeFaces Editor is not supporting "Insert Table" function. So, I want to use CKE.
As el wont be able to evaluate non-JSF component.
Add this to your page :
<h:inputHidden value="#{EditorBean.value}" id="editorValue"/>
and onblur of editor textarea assign the value to the hidden element using
document.getElementById(editorValue).value = this.value;
Since this question bumped up somehow....
There is another option:
You can use the PrimeFaces Extensions , here is the link PrimeFaces Extensions CKEditor
Here an example from the showcase
<p:growl id="growl" showDetail="true" />
<pe:ckEditor id="editor" value="#{editorController.content}" interfaceColor="#33fc14">
<p:ajax event="save" listener="#{editorController.saveListener}" update="growl"/>
</pe:ckEditor>
<p:commandButton actionListener="#{editorController.changeColor}" update="editor"
value="Change color with AJAX" style="margin-top:10px;"/>
try this:
<textarea class="ckeditor" cols="80" id="editor1" rows="10"/>
<h:inputHidden value="#{tskCtrl.selected.dsc}" id="editorValue"/>
<p:commandButton onclick="document.getElementById('editorValue').value = CKEDITOR.instances.editor1.getData();" action="#{tskCtrl.create()}" value="Post" />
The answer from niksvp was helpful and set me in the right direction, but
the problem I found was that the blur handler never fires. I had to copy
the value from the textarea to the inputHidden on the onclick handler of
the commandButton:
<textarea id="textareaValue" .../>
<a4j:commandButton execute="editorValue" onclick="document.getElementById('editorValue').value = document.getElementById('textareaValue').value;"
...
or
<a4j:commandButton execute="editorValue" onclick="jQuery('#editorValue').val(jQuery('#textareaValue').val())"
I tried using onbegin & onbeforedomupdate but they didn't work.
Another option is to use the JSF versions of form and textarea. (It is likely possible to do this with passthrough elements as well, but I didn't try that.)
<h:form id="form">
<p>
My Editor:<br />
<h:inputTextarea cols="90" rows="20" id="editor1" value="#{EditorBean.value}" />
<script type="text/javascript">
ClassicEditor.create(document.querySelector('form\\:editor1'))
.then( editor => {
console.log( editor );
} )
.catch( error => {
console.error( error );
} );
</script>
</p>
</form>
This assumes that you do not have prependId=false.
The weird \\: is an escaping issue. It won't work without that. You'd get the "is an invalid selector" error in the console.
You can ID form and editor1 with other names, but you'll need to change the selector as well. You don't want to leave it to the defaults, as those are fragile, often changing as you update the page. Now it will only change if you change the structure of where editor1 is relative to form. E.g. if you add a fieldset around editor1, that would make the ID something like form\\:fieldset\\:editor1, where fieldset is the ID of the fieldset as specified in JSF. JSF will create the long version for you.
This also requires the CKEditor script to be added to the head, e.g.:
<script src="https://cdn.ckeditor.com/ckeditor5/11.2.0/classic/ckeditor.js"></script>
This particular example is for the ClassicEditor version. If you want a different version, you'd need to change the script and the part that says ClassicEditor.
Differences between the script as called in the question and this version may be that this is the current version (as I write this) while the question is older.
Alternately, you might prefer to use h:outputScript. But then you might need to host the script in your resources folder rather than using the version from the CDN.
See also:
Is the ID generated by JSF guaranteed to be the same across different versions and implementations?
Select element with double dot in id, error: “#octo:cat” is not a valid selector
Acquire full prefix for a component clientId inside naming containers with JSF 2.0
How to find out client ID of component for ajax update/render? Cannot find component with expression “foo” referenced from “bar”
How to include JavaScript files by h:outputScript?

Manage back and forward in Richfaces

I'm using RichFaces component library and I want to manage the history of Ajax navigation, so the enduser can use the browser back and forward buttons.
Is there any clean way to do it, design pattern, library, etc?
You can use RSH to handle Ajax history
For the example lets assume that you have a page where the user should select a color.
Then, the selected color is posted to the server using XmlHttpRequest.
Now we want to restore previous selection when the back and forward navigation buttons is pressed.
Code Example
Bean:
public class Bean {
private static final String DAFAULT_COLOR = "green";
private Map<String, Color> colors;
private Color selectedColor;
private String restoredColor;
#PostConstruct
public void init() {
this.colors = new HashMap<String, Color>();
this.colors.put("green", new Color("Green", "008000"));
this.colors.put("blue", new Color("Blue", "0000FF"));
this.colors.put("red", new Color("Red", "FF0000"));
this.colors.put("purple", new Color("Purple", "FF0000"));
this.colors.put("purple", new Color("Purple", "800080"));
this.colors.put("yellow", new Color("Yellow", "FFFF00"));
this.colors.put("silver", new Color("Silver", "C0C0C0"));
this.colors.put("black", new Color("Black", "000000"));
this.colors.put("white", new Color("White", "FFFFFF"));
this.selectedColor = this.colors.get(DAFAULT_COLOR);
}
public void setSelectedColor(ActionEvent event) {
UIComponent component = event.getComponent();
String color = ((String)component.getAttributes().get("color")).toLowerCase();
this.selectedColor = this.colors.get(color);
}
public void restoreColor() {
if(restoredColor.equals("") || restoredColor.equals("null")) {
restoredColor = DAFAULT_COLOR;
}
this.selectedColor = this.colors.get(restoredColor);
}
public List<Color> getColors() {
return Arrays.asList(colors.values().toArray(new Color[0]));
}
public Color getSelectedColor() {
return selectedColor;
}
public String getRestoredColor() {
return restoredColor;
}
public void setRestoredColor(String restoredColor) {
this.restoredColor = restoredColor.toLowerCase();
}
}
View:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:t="http://myfaces.apache.org/tomahawk"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
template="/WEB-INF/template/default.xhtml">
<ui:define name="head">
<script type="text/javascript" src="#{request.contextPath}/js/rsh/rsh.js"></script>
<script type="text/javascript">
window.dhtmlHistory.create({
toJSON: function(o) {
return Object.toJSON(o);
},
fromJSON: function(s) {
return s.evalJSON();
}
});
Event.observe(window, 'load', function() {
dhtmlHistory.initialize();
dhtmlHistory.addListener(handleHistoryChange);
});
var registerHistoryPoint = function(newLocation, historyData) {
dhtmlHistory.add(newLocation, historyData);
};
</script>
</ui:define>
<ui:define name="content">
<a4j:form id="frmColor">
<div class="colors">
<ul>
<a4j:repeat value="#{bean.colors}" var="color">
<li style="background:##{color.hex};">
<a4j:commandLink value=" "
actionListener="#{bean.setSelectedColor}"
reRender="frmColor"
oncomplete="registerHistoryPoint('#{color.name}', '#{color.name}');">
<f:attribute name="color" value="#{color.name}"/>
</a4j:commandLink>
</li>
</a4j:repeat>
</ul>
</div>
<div class="selection" style="background:##{bean.selectedColor.hex};">
<div class="selected-color"
style="color: ##{bean.selectedColor.name eq 'White' or
bean.selectedColor.name eq 'Yellow' ? '000000' : 'ffffff'}">
<h:outputText value="#{bean.selectedColor.name}"/>
</div>
</div>
<a4j:jsFunction name="handleHistoryChange" reRender="frmColor"
action="#{bean.restoreColor}">
<a4j:actionparam name="historyData" assignTo="#{bean.restoredColor}" />
</a4j:jsFunction>
</a4j:form>
</ui:define>
</ui:composition>
Now when the user click on a color the registerHistoryPoint is invoked. This will register historyData that will be passed to the bean when the back and forward buttons is pressed.
e.g.
User select Yellow.
Yellow is registered.
User select Blue.
Blue is registered.
User click on back.
Yellow is restored.
User click forward.
Blue is restored.

Resources