I have primefaces steps using tag <p:steps> like below :
<p:steps activeIndex="3" styleClass="custom" readonly="false" style="padding: 20px;">
<p:menuitem value="step 1." actionListener="#{masterController.menuSales(preferencesController)}" update="mainPanel"/>
<p:menuitem value="step 2." actionListener="#{masterController.menuCustomer(preferencesController)}" update="mainPanel"/>
<p:menuitem value="step 3." actionListener="#{masterController.menuItem(preferencesController)}" update="mainPanel"/>
<p:menuitem value="step 4"/>
</p:steps>
And the result is like this :
I can click step 1 but not step 3 and 4. How can I enable click for all steps?
Wow, that's a nice question!
I've tried many things with the current API to accomplish it, but seems like it's not possible with our current options.
To solve this I wrote a custom renderer for the Steps component:
Most of the code below is the same from the PrimeFaces's GitHub. I just changed a few things to solve this specific problem.
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.primefaces.component.api.AjaxSource;
import org.primefaces.component.api.UIOutcomeTarget;
import org.primefaces.component.steps.Steps;
import org.primefaces.component.steps.StepsRenderer;
import org.primefaces.model.menu.MenuItem;
import org.primefaces.util.ComponentTraversalUtils;
public class CustomStepsRenderer extends StepsRenderer {
#Override
protected void encodeItem(FacesContext context, Steps steps, MenuItem item, int activeIndex, int index) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String itemClass;
if (steps.isReadonly()) {
itemClass = (index == activeIndex) ? Steps.ACTIVE_ITEM_CLASS : Steps.INACTIVE_ITEM_CLASS;
} else {
if (index == activeIndex) {
itemClass = Steps.ACTIVE_ITEM_CLASS;
}
else {
itemClass = Steps.VISITED_ITEM_CLASS;
}
}
String containerStyle = item.getContainerStyle();
String containerStyleClass = item.getContainerStyleClass();
if (containerStyleClass != null) {
itemClass = itemClass + " " + containerStyleClass;
}
//header container
writer.startElement("li", null);
writer.writeAttribute("class", itemClass, null);
writer.writeAttribute("role", "tab", null);
if (containerStyle != null) {
writer.writeAttribute("style", containerStyle, null);
}
encodeMenuItem(context, steps, item, activeIndex, index);
writer.endElement("li");
}
#Override
protected void encodeMenuItem(FacesContext context, Steps steps, MenuItem menuitem, int activeIndex, int index) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String title = menuitem.getTitle();
String style = menuitem.getStyle();
String styleClass = this.getLinkStyleClass(menuitem);
writer.startElement("a", null);
writer.writeAttribute("tabindex", "-1", null);
if (shouldRenderId(menuitem)) {
writer.writeAttribute("id", menuitem.getClientId(), null);
}
if (title != null) {
writer.writeAttribute("title", title, null);
}
writer.writeAttribute("class", styleClass, null);
if (style != null) {
writer.writeAttribute("style", style, null);
}
if (steps.isReadonly() || menuitem.isDisabled()) {
writer.writeAttribute("href", "#", null);
writer.writeAttribute("onclick", "return false;", null);
} else {
String onclick = menuitem.getOnclick();
//GET
if (menuitem.getUrl() != null || menuitem.getOutcome() != null) {
String targetURL = getTargetURL(context, (UIOutcomeTarget) menuitem);
writer.writeAttribute("href", targetURL, null);
if (menuitem.getTarget() != null) {
writer.writeAttribute("target", menuitem.getTarget(), null);
}
} //POST
else {
writer.writeAttribute("href", "#", null);
UIComponent form = ComponentTraversalUtils.closestForm(context, steps);
if (form == null) {
throw new FacesException("MenuItem must be inside a form element");
}
String command;
if (menuitem.isDynamic()) {
String menuClientId = steps.getClientId(context);
Map<String, List<String>> params = menuitem.getParams();
if (params == null) {
params = new LinkedHashMap<String, List<String>>();
}
List<String> idParams = new ArrayList<String>();
idParams.add(menuitem.getId());
params.put(menuClientId + "_menuid", idParams);
command = menuitem.isAjax()
? buildAjaxRequest(context, steps, (AjaxSource) menuitem, form, params)
: buildNonAjaxRequest(context, steps, form, menuClientId, params, true);
} else {
command = menuitem.isAjax()
? buildAjaxRequest(context, (AjaxSource) menuitem, form)
: buildNonAjaxRequest(context, ((UIComponent) menuitem), form, ((UIComponent) menuitem).getClientId(context), true);
}
onclick = (onclick == null) ? command : onclick + ";" + command;
}
if (onclick != null) {
writer.writeAttribute("onclick", onclick, null);
}
}
writer.startElement("span", steps);
writer.writeAttribute("class", Steps.STEP_NUMBER_CLASS, null);
writer.writeText((index + 1), null);
writer.endElement("span");
Object value = menuitem.getValue();
if (value != null) {
writer.startElement("span", steps);
writer.writeAttribute("class", Steps.STEP_TITLE_CLASS, null);
writer.writeText(value, null);
writer.endElement("span");
}
writer.endElement("a");
}
Then, register this new renderer in your faces-config.xml file:
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.StepsRenderer</renderer-type>
<renderer-class>YOUR_PACKAGE.CustomStepsRenderer</renderer-class>
</renderer>
</render-kit>
Don't forget to change YOUR_PACKAGE to your CustomStepsRenderer package location.
After that, just build/re-deploy your application and everything should work fine:
Well, p:steps and p:wizard are the components in PrimeFaces component suite that represent or indicate the step(s) in a workflow to manage multiple steps of single form (step by step) for process simplication and can be used interchangably if you understand the usage properly (depending on the requirement).
For using p:steps component, you should ensure that the next step(s) will only be displayed when the current step is completely processed and required data is gathered.
Assume the process of online shopping, where payment processing is the last step and that will appear if and only if, you have any item in your cart and have provided the other information (if any).
The above scenario can also be implemented using p:wizard component. Where only current step is processed partially and next step is displayed if current step passes validations. However, p:wizard component has feasibility to override it's default behavior by controlling the wizard flow, rendering of custom previous & next buttons with custom action handlers and skipping of validation to view next steps.
menuform:I may answer your question a bit late, but I will post it so if other persona have the same problem, may it work for them.
I use JavaScript for the solution, so may it not the solution that you need:
// That is your code. I added ids to capture them with the DOM.
<p:steps activeIndex="3" styleClass="custom" readonly="false" style="padding: 20px;">
<p:menuitem value="step 1." actionListener="#{masterController.menuSales(preferencesController)}" update="mainPanel" id="step1"/>
<p:menuitem value="step 2." actionListener="#{masterController.menuCustomer(preferencesController)}" update="mainPanel" id="step2"/>
<p:menuitem value="step 3." actionListener="#{masterController.menuItem(preferencesController)}" update="mainPanel" id="step3"/>
<p:menuitem value="step 4" id="step4"/>
</p:steps>
// Now we can make the script
<script>
// First of all, we will capture all the steps with the DOM (you can also work with jQuery, but I will post the solution with DOM in case you do not have your code prepared to jQuery)
var step1 = document.getElementById("menuform:step1");
var step2 = document.getElementById("menuform:step2");
var step3 = document.getElementById("menuform:step3");
var step4 = document.getElementById("menuform:step4");
// Then, we are going to set the attributes href and onclick, and give them some style to make the elements look like proper links
step1.setAttribute("href", "[url]");
step1.setAttribute("onclick", true);
step1.style.cursor = "pointer";
step2.setAttribute("href", "[url]");
step2.setAttribute("onclick", true);
step2.style.cursor = "pointer";
step3.setAttribute("href", "[url]");
step3.setAttribute("onclick", true);
step4.style.cursor = "pointer";
step4.setAttribute("href", "[url]");
step4.setAttribute("onclick", true);
step4.style.cursor = "pointer";
</script>
Is important to change href and onclick (click event), because the element 'steps' change both of them, thats like them looks like when you inspect the code with the console:
- href="#"
- onclick="return false;"
Related
I have an inputtextarea which calls a completeMethod after a query is entered... that is working fine and the suggestions are displaying, but I woul'd need to catch the ajax event in order to know which suggestion the user has picked. Is it possible?
You are trying to use the ajax itemSelect event like so:
<h:form>
<p:inputTextarea widgetVar="textarea" completeMethod="#{myBean.complete}">
<p:ajax event="itemSelect" listener="#{myBean.onSelect}" />
</p:inputTextarea>
</h:form>
Managed bean methods:
public List<String> complete(String filter) {
List<String> result = new ArrayList<String>();
for (int i = 0; i < 10; i++)
result.add(filter + i);
return result;
}
public void onSelect(SelectEvent<String> e) {
System.out.println(e.getObject());
}
This does not work in Primefaces 7.0 (and probably earlier) because the renderer of the inputTextarea fails to add the clientBehavior configuration which is fixed as of Version 7.1.
In the browser javascript console input:
PF('textarea').cfg.behaviors
> undefined
The result undefined indicates missing client behavior configuration.
You can work around this by overriding the InputTextareaRenderer.encodeScript() method:
package my.package;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.primefaces.component.inputtextarea.InputTextarea;
import org.primefaces.component.inputtextarea.InputTextareaRenderer;
import org.primefaces.expression.SearchExpressionFacade;
import org.primefaces.util.WidgetBuilder;
public class CustomInputTextareaRenderer extends InputTextareaRenderer {
#Override
protected void encodeScript(FacesContext context, InputTextarea inputTextarea) throws IOException {
String clientId = inputTextarea.getClientId(context);
boolean autoResize = inputTextarea.isAutoResize();
String counter = inputTextarea.getCounter();
WidgetBuilder wb = getWidgetBuilder(context);
wb.init("InputTextarea", inputTextarea.resolveWidgetVar(), clientId).attr("autoResize", autoResize)
.attr("maxlength", inputTextarea.getMaxlength(), Integer.MAX_VALUE);
if (counter != null) {
UIComponent counterComponent = SearchExpressionFacade.resolveComponent(context, inputTextarea, counter);
wb.attr("counter", counterComponent.getClientId(context)).attr("counterTemplate",
inputTextarea.getCounterTemplate(), null);
}
if (inputTextarea.getCompleteMethod() != null) {
wb.attr("autoComplete", true).attr("minQueryLength", inputTextarea.getMinQueryLength())
.attr("queryDelay", inputTextarea.getQueryDelay())
.attr("scrollHeight", inputTextarea.getScrollHeight(), Integer.MAX_VALUE);
}
// additional line enabling AJAX 'itemSelect' event handling.
encodeClientBehaviors(context, inputTextarea);
wb.finish();
}
}
In faces config, add the renderer:
<faces-config>
...
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.InputTextareaRenderer</renderer-type>
<renderer-class>my.package.CustomInputTextareaRenderer</renderer-class>
</renderer>
</render-kit>
</faces-config>
Quick indication that it works in javascript console:
PF('textarea').cfg.behaviors
> Object { itemSelect: itemSelect() }
I faced problem with disabling RichFaces sorting by column on button click.
Maybe someone can help
I have AlertsList datatable:
<rich:extendedDataTable id="#{module}AlertsList"
tableState="#{alertsController.dataModel.tableState}"
enableContextMenu="false"
height="220px"
sortMode="single"
value="#{alertsController.dataModel}"
var="alert" width="100%"
selection="#{alertsController.selection}"
reRender="#{module}AlertsListDatascroller"
rows="#{alertsController.dataModel.rowsPerPage}"
binding="#{alertsController.dataModel.extandetDataTable}"
rowClasses="evenRow,oddRow">
......
<rich:column sortBy="#{alert.lockedByUsername}" width="7%"
style="#{(not empty alert.first4OfLockedByUsername and (alertsController.dataModel.selectedItem != alert)) ? 'background-color: darkgray' : ((alert.action != null and alert.action.classificationTypeEntity.classificationType eq 'POSTPONED') ? 'background-color: thistle' : '')}"
label="#{message['alertsnalysis.alertList.table.lock']}"
selfSorted="#{currentUser.authorities['SVWI_MODIFICATION']}"
id="#{module}AL_lockedByUsername">
<f:facet name="header">#{message['alertsnalysis.alertList.table.lock']}</f:facet>
<h:outputText value="#{alert.first4OfLockedByUsername}" />
</rich:column>
......
<rich:column sortBy="#{alert.id}" width="5%"
style="#{(not empty alert.first4OfLockedByUsername and (alertsController.dataModel.selectedItem != alert)) ? 'background-color: darkgray' : ((alert.action != null and alert.action.classificationTypeEntity.classificationType eq 'POSTPONED') ? 'background-color: thistle' : '')}"
label="#{message['alertsnalysis.alertList.table.id']}"
selfSorted="#{currentUser.authorities['SVWI_MODIFICATION']}"
id="#{module}AL_id">
<f:facet name="header">#{message['alertsnalysis.alertList.table.id']}</f:facet>
<h:outputText value="#{alert.id}" />
</rich:column>
....
<rich:datascroller id="#{module}AlertsListDatascroller" for="#{module}AlertsList" ajaxSingle="false" page="#{alertsController.dataModel.currentPage}"></rich:datascroller>
So I added button to change soring table results by 3 columns at a time, cause due my current realisation i cant sorting data by clicking on different column headers(way with sortMode="multiply" is not accepted):
<h:form id="buttonReset">
<h:panelGrid columns="2">
<a4j:commandButton id="resetSortingButton" styleClass="FatButtonStyle" reRender="#{module}AlertsList"
action="#{alertsController.dataModel.defaultSortField}" value="Default Sorting"/>
</h:panelGrid>
</h:form>
Also I have implementaion of Modifiable:
public abstract class TableDataModel<T, U> extends SerializableDataModel implements Modifiable, Serializable {
...
protected String sortField = null;
..
public void defaultSortField(){ // call on button "Default Sorting" click action
this.sortField = "default"; //set field to default
this.detached = false;
this.defaultFlag = true;
this.i = 0;
}
...
#Override
public void walk(final FacesContext context, final DataVisitor visitor, final Range range, final Object argument)
throws IOException {
final int firstRow = ((SequenceRange) range).getFirstRow();
final int numberOfRows = ((SequenceRange) range).getRows();
if (detached) {
for (final U key : wrappedKeys) {
setRowKey(key);
visitor.process(context, key, argument);
}
} else {
List<T> list = Collections.<T>emptyList();
if (rangeChanged((SequenceRange) range) || sortChanged(sortField) || filterMapChanged(filterMap) || descChanged(descending) || ((MethodReRendering) this).getReRenderingEnabled()) {
lastRange = (SequenceRange) range;
lastSortField = sortField;
lastFilterMap = new HashMap<String, Object>(filterMap);
lastDescending = descending;
((MethodReRendering) this).setReRenderingEnabled(false);
list = findObjects(firstRow, numberOfRows, sortField, filterMap, descending); //in findObjects() checking if sortField == "default", then sorting by 3 columns, else by column in field value
wrappedKeys = new CopyOnWriteArrayList<U>();
for (final T object : list) {
wrappedKeys.add(getId(object));
wrappedData.put(getId(object), object);
visitor.process(context, getId(object), argument);
}
} else {
for (U id :wrappedKeys)
visitor.process(context, id, argument);
}
}
}
...
public void modify(List<FilterField> filterFields, List<SortField2> sortFields) {
filterMap.clear();
SortField2 sortField2 = null;
String expressionStr = null;
ExtendedFilterField extendedFilterField = null;
String value = null;
Expression expression = null;
if (sortFields != null && !sortFields.isEmpty()) {
sortField2 = sortFields.get(0);
expression = sortField2.getExpression();
......
}
...
}
So problem is when I click my btn I change sortField value and walk() method returns new sorted by 3 columns data to my table ( see findObjects(firstRow, numberOfRows, sortField, filterMap, descending);).
All works fine.
But on my page I still can see (by icon or if i refresh my page it calls modify() method with List sortFields parameter == "alertId") that means what data still sorted by alertId column, but new sorting implemented. What logic I need add to my defaultSortField() method (calls on "Default Sorting" button click), for disable sorting by alertId column?
UPDATE1:
Added binding my extendedDataTable to property:
But maybe someone know how can I disable current sorting?
UIExtendedDataTable extandetDataTable = null;
public void setExtandetDataTable(UIExtendedDataTable extandetDataTable) {
this.extandetDataTable = extandetDataTable;
List<SortField2> sortField2s = extandetDataTable.getSortFields();
SortField2 sortField2;
}
public UIExtendedDataTable getExtandetDataTable() {
return extandetDataTable;
}
Why can't you use the sortMode=multi?
The table also has sortPriority - a list of ids by which to sort, I assume your not adding the ids of the columns to the sortPriority so it gets sorted by the id that is there. The handling is done in org.richfaces.renderkit.SortingFilteringRowsRenderer.decodeSorting().
EDIT: If you want to disable sorting you can set sortType="custom" on rich:column, but I don't know if that won't interfere with your implementation.
I'm trying primefaces 4 but there are no documentation around for the new MenuModel. Here, Optimus Prime wrote about the new menu system with a little example.
http://blog.primefaces.org/?p=2594
At this point, he wrote about a setCommand method:
This point to a save method (found in the pf4 showcase: http://www.primefaces.org/showcase/ui/menu/menu.xhtml):
After this introduction, here's the question/problem. I'm creating a dynamic menu from a bean but I don't understand how know the menu clicked by the user and do the right operation.
public void init() {
if (spBean == null) {
System.out.println("spBean is NULL!");
return;
}
for (ServiceProvider sp: spBean.getListaSP()) {
DefaultMenuItem item = new DefaultMenuItem(sp.getNome());
//item.setUrl("#");
item.setIcon("images/sps/" + sp.getImageId() + ".png");
item.setCommand("#{dockMenuBackingBean.setNewMenu}");
//
model.addElement(item);
System.out.println(sp.getNome());
}
}
public void setNewMenu() {
System.out.println("A menu was clicked BUT witch menu? Arghh!!");
//
}
What I want to do, is to change the spSelected in ServiceProviderBackingBean, like I've done in PF3.5:
<p:dock>
<c:forEach items="#{serviceProvidersBean.sps}" var="sp">
<p:menuitem
value="#{sp.spInstanceName}"
icon="/images/sps/#{sp.spInstanceId}.png"
update=":form:spDetail" >
<f:setPropertyActionListener
value="#{sp}"
target="#{serviceProvidersBean.spSelected}" />
</p:menuitem>
</c:forEach>
</p:dock>
Any help?
EDIT:
Actually I'm doing this, but I'm looking for a better and cleaner way to achieve this.
public void init() {
if (spBean == null) {
System.out.println("spBean is NULL!");
return;
}
for (ServiceProvider sp: spBean.getListaSP()) {
DefaultMenuItem item = new DefaultMenuItem(sp.getNome());
//item.setUrl("#");
item.setIcon("images/sps/" + sp.getImageId() + ".png");
String command = String.format("#{dockMenuBackingBean.setNewMenu('%d')}", spBean.getListaSP().indexOf(sp));
item.setCommand(command);
//
model.addElement(item);
System.out.println(sp.getNome());
}
}
public void setNewMenu(Object x) {
Integer selectedId = Integer.parseInt((String)x);
System.out.println("Menu changed " + Integer.toString(selectedId));
//
}
Setting command parameters by setParam(key,value) can be done like that:
In your menu generating bean:
DefaultMenuItem item = new DefaultMenuItem("display list");
item.setId("listMenuItem");
item.setCommand("#{myBean.displayList}");
item.setParam("listId", 1l);
In your managed bean containing the action:
public String displayList(ActionEvent event) {
MenuItem menuItem = ((MenuActionEvent) event).getMenuItem();
Long id = Long.parseLong(menuItem.getParams().get("listId").get(0));
findListBy(id);
}
Reading parameters seems to be a bit complicated. But ActionListeners aren't supported by Primefaces 4 MenuItems (because they aren't derived from UICommand any more) so params seem to be new new way.
Optimus here, use setParam(key,value). You need to update to trunk code though for this.
Is it possible to override renderer used by <h:selectOneRadio>? I tried to find the class from jsf-impl package of JSF 2.2 but didn't find it. The reason I want to do this is to get rid of the table it generates.
Is it possible to override renderer used by h:selectOneRadio?
Yes, surely it is. Otherwise, UI component libraries like PrimeFaces couldn't exist.
I tried to find the class from jsf-impl package but didn't find it.
The exact class depends on the JSF implementation you're using. If it's Mojarra, then it's the com.sun.faces.renderkit.html_basic.RadioRenderer class. If it's MyFaces, then it's the org.apache.myfaces.renderkit.html.HtmlRadioRenderer class.
In order to properly override it, just extend the class and override methods where necessary and register it as follows in your faces-config.xml:
<render-kit>
<renderer>
<component-family>javax.faces.SelectOne</component-family>
<renderer-type>javax.faces.Radio</renderer-type>
<renderer-class>com.example.MyRadioRenderer</renderer-class>
</renderer>
</render-kit>
Keep in mind that you're this way tight-coupling the renderer to the specific JSF impl/version. Such an extended renderer is not compatible with a different JSF implementation (i.e. your app wouldn't deploy when you ever replace Mojarra by MyFaces) and may possibly break when the current JSF implementation has been updated to a newer version. If you worry about this, consider writing the renderer entirely from scratch, like PrimeFaces et.al. do.
The reason I want to do this is to get rid of the table it generates.
Consider looking at Tomahawk or PrimeFaces instead of reinventing the wheel. They have respectively a <t:selectOneRadio layout="spread"><t:radio> and <p:selectOneRadio layout="custom"><p:radioButton> which allows you positioning those things everywhere you want.
See also:
<h:selectOneRadio> renders table element, how to avoid this?
I added
<render-kit>
<renderer>
<component-family>javax.faces.SelectOne</component-family>
<renderer-type>javax.faces.Radio</renderer-type>
<renderer-class>com.sial.ecommerce.configurator.ui.model.RadioRendererWithoutDataTable</renderer-class>
</renderer>
</render-kit>
to faces-config.xml.
And created a class which extends com.sun.faces.renderkit.html_basic.RadioRenderer And I did override the method encodeEnd then commented out the code which adding table elements.
public class RadioRendererWithoutDataTable extends com.sun.faces.renderkit.html_basic.RadioRenderer {
#Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
rendererParamsNotNull(context, component);
if (!shouldEncode(component)) {
return;
}
ResponseWriter writer = context.getResponseWriter();
assert (writer != null);
String alignStr;
Object borderObj;
boolean alignVertical = false;
int border = 0;
if (null != (alignStr = (String) component.getAttributes().get("layout"))) {
alignVertical = alignStr.equalsIgnoreCase("pageDirection");
}
if (null != (borderObj = component.getAttributes().get("border"))) {
border = (Integer) borderObj;
}
Converter converter = null;
if (component instanceof ValueHolder) {
converter = ((ValueHolder) component).getConverter();
}
// renderBeginText(component, border, alignVertical, context, true);
Iterator<SelectItem> items = RenderKitUtils.getSelectItems(context, component);
Object currentSelections = getCurrentSelectedValues(component);
Object[] submittedValues = getSubmittedSelectedValues(component);
Map<String, Object> attributes = component.getAttributes();
OptionComponentInfo optionInfo = new OptionComponentInfo((String) attributes.get("disabledClass"),
(String) attributes.get("enabledClass"), (String) attributes.get("unselectedClass"),
(String) attributes.get("selectedClass"), Util.componentIsDisabled(component), isHideNoSelection(component));
int idx = -1;
while (items.hasNext()) {
SelectItem curItem = items.next();
idx++;
// If we come across a group of options, render them as a nested
// table.
if (curItem instanceof SelectItemGroup) {
// write out the label for the group.
if (curItem.getLabel() != null) {
// if (alignVertical) {
// writer.startElement("tr", component);
// }
//writer.startElement("td", component);
writer.writeText(curItem.getLabel(), component, "label");
// writer.endElement("td");
// if (alignVertical) {
// writer.endElement("tr");
// }
}
// if (alignVertical) {
// writer.startElement("tr", component);
// }
// writer.startElement("td", component);
// writer.writeText("\n", component, null);
// renderBeginText(component, 0, alignVertical, context, false);
// render options of this group.
SelectItem[] itemsArray = ((SelectItemGroup) curItem).getSelectItems();
for (int i = 0; i < itemsArray.length; ++i) {
renderOption(context, component, converter, itemsArray[i], currentSelections, submittedValues, alignVertical, i,
optionInfo);
}
// renderEndText(component, alignVertical, context);
// writer.endElement("td");
// if (alignVertical) {
// writer.endElement("tr");
// writer.writeText("\n", component, null);
// }
} else {
renderOption(context, component, converter, curItem, currentSelections, submittedValues, alignVertical, idx, optionInfo);
}
}
//renderEndText(component, alignVertical, context);
}
Then it worked for me.
When I given
<h:selectOneRadio >
<f:selectItem itemValue="1" itemLabel="Item 1" />
<f:selectItem itemValue="2" itemLabel="Item 2" />
</h:selectOneRadio>
in my jsf page.
It converted to
<input type="radio" name="bulkForm:j_idt224" id="bulkForm:j_idt224:0" value="1"><label for="bulkForm:j_idt224:0"> Item 1</label>
<input type="radio" name="bulkForm:j_idt224" id="bulkForm:j_idt224:1" value="2"><label for="bulkForm:j_idt224:1"> Item 2</label>
which was what I need.
I'm using jsf 2.1 and Primefaces 3.3. I want to show the total number of errors within a page at the top of the page using <p:message>.
Please give me advice for how to do it and it will be helpful if you can explain with an example. Thank you in advance.
If you just want to count specific messages (e.g. only errors). you can do something like this:
#ManagedBean
#RequestScoped
public class MessageCount {
public int getFatal() {
return countMessages(FacesMessage.SEVERITY_FATAL);
}
public int getError() {
return countMessages(FacesMessage.SEVERITY_ERROR);
}
public int getWarn() {
return countMessages(FacesMessage.SEVERITY_WARN);
}
public int getInfo() {
return countMessages(FacesMessage.SEVERITY_INFO);
}
private int countMessages(FacesMessage.Severity severity) {
Iterator<FacesMessage> iterator = FacesContext.getCurrentInstance().getMessages();
int count = 0;
while (iterator.hasNext()) {
FacesMessage msg = iterator.next();
if (severity.compareTo(msg.getSeverity()) == 0) {
count++;
}
}
return count;
}
}
And in your jsf page:
<h:outputText value="#{messageCount.error}"/>
Why use <p:message/> ?
Try this
<h:outputText value="#{fn:length(facesContext.messageList)}"/>
There is no built in functionality for this. You can for example add inputHidden element to form, and add p:message for that input hidden field:
<p:messages for="justForErrorCount"/>
<h:inputHidden id="justForErrorCount"/>
In your backing bean you can do some check and add message:
if (FacesContext.getCurrentInstance().getMessageList() != null &&
!FacesContext.getCurrentInstance().getMessageList().isEmpty()) {
String message = "You have " +
FacesContext.getCurrentInstance().getMessageList().size() + " errors";
FacesContext.getCurrentInstance().addMessage("justForErrorCount",
new FacesMessage(FacesMessage.SEVERITY_ERROR, message);
}