We are migrating an application from jsf 1.2 to jsf 2.0, and upgrading Ajax4JSF (ajax4jsf-1.1.1) to Richfaces 4.2.2.
In our old code, there are places where we use org.ajax4jsf.framework.ajax.AjaxActionComponent to programmatically set the 'rerender' attribute of some components. The relevant code is as follows:
public void changeReRender(UIComponent comp){
AjaxActionComponent commandAjax = (AjaxActionComponent)comp;
HashSet values = new HashSet();
values.add("idToBeRerendered");
commandAjax.setReRender(values);
}
But in Richfaces 4 the AjaxActionComponent class was removed.
Is there a class that can be used instead of AjaxActionComponent, or another way to programmatically change the 'rerender' attribute of UIComponent?
In JSF2, there's a more generic approach to programmatically rendering ids using the PartialViewContext object. Try the following snippet
public void changeReRender(UIComponent comp){
// AjaxActionComponent commandAjax = (AjaxActionComponent)comp;
// HashSet values = new HashSet();
// values.add("idToBeRerendered");
// commandAjax.setReRender(values);
FacesContext context = FacesContext.getCurrentInstance();
PartialViewContext partialContext = context.getPartialViewContext(); //obtain a reference to the PartialViewContext object
//add the desired id to the list of render ids
partialContext.getRenderIds().add("idToBeRerendered");
}
Related
I need to create a custom component that either extend or include a Primefaces SelectOneMenu. This is done so that I can deliver the select items based on the field (for now, they are hardcoded in the example below and the tag is properly registered).
The component is rendered and the select items are also displayed fine. However, when I save, the record's field is not updated with the selected item's value. Is there some primeface method I should override to actually set the value?
Are there any tutorials on how to extend primeface (or atleast jsf) components? I could hardly find any. Thank you in advance
#FacesComponent(value = ComponentRegistry.INPUT_SELECTDROPDOWN_COMPONENT_TYPE)
public class InputSelectDropdown extends SelectOneMenu {
#Override
public void encodeBegin(FacesContext context) throws IOException {
this.setValueExpression("value", this.getValueExpression("value"));
UISelectItem select1 = new UISelectItem();
select1.setItemLabel("item 1");
select1.setItemValue("item1");
select1.encodeAll(context);
this.getChildren().add(select1);
UISelectItem select2 = new UISelectItem();
select2.setItemLabel("item 2");
select2.setItemValue("item2");
select2.encodeAll(context);
this.getChildren().add(select2);
super.encodeBegin(context);
}
}
I have a dynamically generated Datatable, like this
DataTable dataTable = new DataTable();
dataTable.setValue(relatorioVOList);
dataTable.setVar("rVO");
Column checkBoxColumn = new Column();
checkBoxColumn.getChildren().add(this.viewComponentBuilder.createExpressionTextWithLink("#{rVO.iRelatorio}","#{rVO.nNome}"));
dataTable.getColumns().add(checkBoxColumn);
public HtmlForm createExpressionTextWithLink(String iRelatorioExpressionValue, String valueExpressionValue) {
HtmlForm form = new HtmlForm();
HtmlCommandLink link = new HtmlCommandLink();
//config
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
ExpressionFactory ef = application.getExpressionFactory();
ELContext elc = context.getELContext();
//value that is the reports name
ValueExpression nameValueExp = ef.createValueExpression(elc, valueExpressionValue, Object.class);
link.setValueExpression("value", nameValueExp);
//action that goes to method teste when link is clicked
MethodExpression methodExpression = createMethodExpression("#{componenteC.teste(rVO.iRelatorio)}", String.class, Integer.class);
link.setActionExpression(methodExpression);
form.getChildren().add(link);
return form;
}
private static MethodExpression createMethodExpression(String expression, Class<?> returnType, Class<?>... parameterTypes) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory().createMethodExpression(
facesContext.getELContext(), expression, returnType, parameterTypes);
}
In ComponenteC, a RequestScopedBean, the teste function
public String teste(Integer iRelatorio) {
System.out.println("cheguei");
return "componente";
}
The goal is that the teste function will generate an url according to the iRelatorio parameter.
The issue here is that the function is never called. I tried replacing the rVO.iRelatorio with an explicit 10, "#{componenteC.teste(10)}" and even then the action seems to not be fired.
The report name is displayed correctly.
Dynamically created UIInput, UICommand and UINamingContainer components must have a fixed id assigned. Otherwise it will get an autogenerated one which is not necessarily the same when the view is restored. The component ID is used in request parameter names in submitted form data, which JSF would then use to collect the submitted input values and identify the invoked commands during apply request values phase. If the component ID changes, then JSF won't be able to perform the apply request values phase as intented.
Thus, act accordingly:
dataTable.setId("tableId");
// ...
form.setId("formId");
// ...
link.setId("linkId");
There are other potential causes, but they are not visible in the information provided so far in the question. To cover that, take your time to carefully read the following related answers on "dynamically" creating components/views:
Create inputtext dynamically
How does the 'binding' attribute work in JSF? When and how should it be used?
How to create dynamic JSF form fields
That said, you're really better off using XHTML to declare and create components instead of all that Java code mess. XHTML(+XML) is much more declarative and readable and therefore better understandable and maintainable. JSTL may be very helpful in this all.
I'm developing a dynamic form using Mojarra 2.2.5 and Primefaces 4.0 and i need to implement a datatable with dynamic content. Unfortunately when i try to submit form appears this error:
java.lang.NumberFormatException: Trying to extract rowIndex from clientId 'id_of_my_datatable:j_id1:j_id1'
I generated datatable by code using it, inspired by Primefaces Showcase (http://primefaces.org/showcase/ui/datatableDynamicColumns.jsf) and from (Stack Overflow discussion)
private DataTable addList(UIComponent parent, String labelStr, String id, List<ColumnModel> rowItems, List<Map<String, String>> values, String styleClass,
boolean isRequired, String updateComponents)
{
OutputPanel outputPanel = new OutputPanel();
outputPanel.setStyleClass("question_panel col-md-11");
if (labelStr != null)
{
addLabel(outputPanel, id, labelStr, "component_label col-md-11");
}
DataTable dataTable = new DataTable();
dataTable.setValue(values);
//mapModel = values;
//ValueExpression veTable = super.createValueExpression("#{composerTestBean.mapModel}", List.class);
//dataTable.setValueExpression("value", veTable);
dataTable.setVar("model");
dataTable.setId(id);
dataTable.setRowIndexVar("rowIndex");
Columns columns = new Columns();
columns.setValue(rowItems);
//columnModel = rowItems;
//ValueExpression veColumns = super.createValueExpression("#{composerTestBean.columnModel}", List.class);
//columns.setValueExpression("value", veColumns);
columns.setVar("column");
columns.setColumnIndexVar("colIndex");
HtmlOutputText headerText = new HtmlOutputText();
ValueExpression veHeader = super.createValueExpression("#{column.header}", String.class);
headerText.setValueExpression("value", veHeader);
columns.getFacets().put("header", headerText);
HtmlOutputText valueText = new HtmlOutputText();
ValueExpression veValue = super.createValueExpression("#{model[column.property]}", String.class);
valueText.setValueExpression("value", veValue);
columns.getChildren().add(valueText);
dataTable.getChildren().add(columns);
outputPanel.getChildren().add(dataTable);
parent.getChildren().add(outputPanel);
return dataTable;
}
As you can see I've also tried to use valueExpression and the property bean binding, but nothing is changed. setRowIndexVar() and setColumnIndexVar() methods are just attempts to resolve the question.
I also read that it could be a Mojarra bug on this discussion (it should be resolved) and in another one that is a Primefaces bug (I can't apply patches on project libraries).
Also I try to follow this post and this remove this exception but brings others problem to my page about update.
Do You think I'm doing something wrong? Or Is it just an unresolvable case?
Thanks in advance.
I have an issue with the attributes values of a validator component.
Apparently the validator is created when I first visit a page.
Please see my code below:
<h:inputText value="#{qsetting.value}" rendered="#{qsetting.dataType=='Double'}">
<mw:validateRange min="#{qsetting.minValue}" max="#{qsetting.maxValue}" />
</h:inputText>
The inputText component is rerendered through ajax but apparently, including the value that is displayed.
Unfortunately, the qsetting.minValue and qsetting.maxValue are not refreshed, causing my validator to not work correctly.
Is there a possibility to refresh the validator, to make sure it re-retrieves its attributes or to just create a new instance of the validator?
The validator class itself is currently implementing "Validator, Serializable".
Also, I'm using jsf1.2 with facelets...
Thanks,
Steven
I've hit this problem in a non-ajax environment a few times over the years, and hit it again today. The addition of Ajax doesn't really change anything since a validator attribute is never evaluated again once the page is initially built, ajax or otherwise.
The only solution I've come up with is to set the validator attribute to a validator expression, then evaluate that expression inside the validate method.
One other issue I hit (also with JSF 1.2 and Facelets) is that not all EL variables worked. I had to use a static managed bean as the root of my expression to access the value. A facelet ui:param value as a root would not work. I haven't tested to see what else may not correctly evaluate. This could be due to another bug in the design of JSF itself. See http://myfaces.apache.org/core12/myfaces-api/apidocs/javax/faces/context/FacesContext.html#getELContext%28%29.
For example, instead of:
max="#{qsetting.maxValue}"
use
maxExpression="qsetting.maxValue"
Then
public String getMax(FacesContext context) {
Application app = context.getApplication();
ExpressionFactory exprFactory = app.getExpressionFactory();
ValueExpression ve = exprFactory.createValueExpression(context.getELContext(),
"#{" + getMaxExpression() + "}",
String.class);
Object result = ve.getValue(context.getELContext());
return (String)result;
}
public String getMaxExpression() {
return this.maxExpression;
}
public void setMaxExpression(String maxExpression) {
this.maxExpression = maxExpression;
}
//// StateHolder
public boolean isTransient() {
return isTransient;
}
public void setTransient(boolean newTransientValue) {
isTransient = newTransientValue;
}
public Object saveState(FacesContext context) {
Object[] state = new Object[1];
state[0] = maxExpression;
return state;
}
public void restoreState(FacesContext context, Object state) {
Object[] values = (Object[]) state;
maxExpression = (String) values[0];
}
UPDATE 2012-09-19:
After investigating how MyFaces Commons solves this problem, the better solution is to change the rules Facelets uses to evaluate validator and converter attribute expressions.
It basically comes down to adding a new validator or converter MetaRule which, when applied, checks to see if the attribute value is non-literal. If it is non-literal, call a special method on your validator or converter which passes in the value expression rather than the current value.
http://svn.apache.org/viewvc/myfaces/commons/trunk/myfaces-commons-validators/src/main/java/org/apache/myfaces/commons/validator/_ValidatorRule.java?view=markup
The validator at that point needs to store the value expression as state and evaluate it when needed. MyFaces commons provides all of the complicated infrastructure to make this happen generically, but you could dump all of that and write a simple custom rule and directly manage the ValueExpression yourself, similar to what I originally posted.
I know about startElement, endElement, and writeAttribute methods on ResponseWriter. My problem is that I want to for example output a h:commandLink by declaring it like HtmlCommandLink link = new HtmlCommandLink(); .
How can I output other UIComponents like this in my own component? I might want to use some RichFaces ajax stuff in my components aswell so hoping I can avoid making it all by scratch.
Edit: What I'm trying to do is create my own tag library with the following tag <myTags:commentTree>. Every comment have a reply button, when the reply button is clicked I render the reply form beneath the comment. Once that is rendered, I would like to output for example the richfaces <a4j:commandButton> component. This have to be done inside my own java tag file which Ive called for CommentsTreeUI.java.
Normally I output all my elements that display the forms and buttons with writer.startElement("input", myComponent); writer.writeAttribute("type", "button", null); but if I could instead do for example startElement("a4j:commandbutton", myComponent) that would help my ALOT since it has all the built in ajax features etc.
Any clues?
This problem was solved by adding new components by using
HtmlCommandButton button = new HtmlCommandButton();
button.encodeAll(context);
You can do something like this:
HtmlCommandLink link = new HtmlCommandLink();
getChildren().add(link);
It does depend on what you want to do with the child components though i.e. if you want them surrounded with custom HTML (in an HTML list, for example) you will need something a bit more complex.
One approach to making composite controls is to use the binding attribute to associate the tag with your own code:
<f:view>
<h:form>
<h:panelGroup binding="#{compositeControlBean.panelGrid}" />
</h:form>
</f:view>
The bean configuration in faces-config.xml:
<managed-bean>
<managed-bean-name>compositeControlBean</managed-bean-name>
<managed-bean-class>
composite.CompositeControlBean
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
The bean code:
/**
* Configure this bean in request scope as "compositeControlBean".
*/
public class CompositeControlBean {
private transient UIComponent panelGrid;
public UIComponent getPanelGrid() {
if (panelGrid == null) {
panelGrid = createCompositePanel();
}
return panelGrid;
}
public void setPanelGrid(UIComponent panelGrid) {
this.panelGrid = panelGrid;
}
private UIComponent createCompositePanel() {
initContextMemebers();
UIComponent commandLink = createCommandLink();
String id = view.createUniqueId();
UIComponent panelGrid = application
.createComponent("javax.faces.HtmlPanelGroup");
panelGrid.setId(id);
panelGrid.setRendererType("javax.faces.Group");
panelGrid.getChildren().add(commandLink);
return panelGrid;
}
private UIComponent createCommandLink() {
// create control
String id = view.createUniqueId();
UIComponent commandLink = application
.createComponent("javax.faces.HtmlCommandLink");
commandLink.setId(id);
commandLink.setRendererType("javax.faces.Link");
// set attributes (bind to printHello method)
Map<String, Object> attributes = commandLink
.getAttributes();
MethodExpression action = expressionFactory
.createMethodExpression(elContext,
"#{compositeControlBean.printHello}",
String.class, new Class<?>[0]);
attributes.put("value", "print hello");
attributes.put("actionExpression", action);
return commandLink;
}
private transient FacesContext context;
private transient Application application;
private transient ELContext elContext;
private transient ExpressionFactory expressionFactory;
private transient UIViewRoot view;
private void initContextMemebers() {
context = FacesContext.getCurrentInstance();
application = context.getApplication();
elContext = context.getELContext();
expressionFactory = application.getExpressionFactory();
view = context.getViewRoot();
}
public String printHello() {
System.out.println("Hello");
return null;
}
}