resetValue in custom UIInput Composite Component not working - jsf-2

I have a custom UIInput wrapped in a composite component like this:
<cc:interface componentType="SingleUpload">
<cc:attribute name="value" required="true" />
...
</cc:interface>
<cc:implementation>
...
<p:fileUpload id="fileUpload" update="#form" auto="true"
fileUploadListener="#{cc.fileUploaded}" rendered="#{cc.attrs.value == null}"/>
...
<h:commandButton rendered="#{cc.attrs.value != null}" action="#{cc.removeFile}">
<p:ajax execute="#this" update="#form" />
</h:commandButton>
...
</cc:implementation>
The backing component looks like this:
#FacesComponent(value = "SingleUpload")
public class SingleUpload extends UIInput implements NamingContainer, Serializable {
/** */
private static final long serialVersionUID = 2656683544308862007L;
#Override
public String getFamily() {
return "javax.faces.NamingContainer";
}
public void fileUploaded(FileUploadEvent event) throws IOException {
FileData file = new FileData();
file.setContentMimeType(MimeTypeUtils.getContentType(event.getFile().getContentType(), event.getFile().getFileName()));
file.setInputStream(event.getFile().getInputstream());
file.setName(FilenameUtils.getName(event.getFile().getFileName()));
setValue(file);
}
public void removeFile() {
resetValue();
// value should be null now, but it is not, why??
FileData value=(FileData) getValue();
}
}
It is used this way:
<ki:singleUpload value="#{fileModel.file}" title="File Upload" />
So when the action removeFile is called, i want to set the value to null. This works, when I follow these steps:
load a page containing a singleUpload component with no initial value (fileModel.file == null)
upload a file, so value in SingleUpload is not null anymore
remove the file
But when I do the following
load a page containing a singleUpload component with an initial value (fileModel.file != null)
remove the intial value (click on button, removeFile is called)
=> removing the value from the component does not seem to be possible. Why??

Related

Validating required on composite component with multiple inputs

I am using a composite component that uses a dropdown and input. The required attribute is set on the dropdown but if 'Other' is selected, then the input should also be required. I guess the required field is being validated on the 'cc.attr.value', but I also need to validate 'cc.attr.otherValue'. So, I am using the postValidate to check this required value. Clicking save should validate the inputs inside the component and then call the postValidate action. However, after postValidate, it is still calling the setter in the update models phase.
<composite:interface componentType="myInputComponent">
<composite:attribute name="value" required="true" type="java.lang.String" />
<composite:attribute name="otherValue" required="true" type="java.lang.String" />
</composite:interface>
<composite:implementation>
<s:validateAll>
<s:span id="input">
<h:selectOneMenu id="selectInput" value="#{cc.attrs.value}"
required="#{cc.required}"
onchange="otherInput = #{rich:element('otherInput')}; otherInput.value = ''; if (this.options[this.selectedIndex].text == 'Other') { otherInput.style.display = ''; otherInput.required = #{cc.required}; } else { otherInput.style.display = 'none'; otherInput.required = false; }">
<f:event type="postValidate" listener="#{cc.postValidate}" />
<!-- validators here -->
</h:selectOneMenu>
<s:span id="other">
<h:inputText id="otherInput" value="#{cc.attrs.otherValue}"
size="#{cc.attrs.width}" style="#{showOther ? '' : 'display: none'}"
onkeydown="#{not cc.attrs.inplace ? 'ignoreEnter(event)' : ''}"
onkeypress="#{cc.attrs.inplace ? 'saveOnEnter(event)' : ''}">
<f:event type="postValidate" listener="#{cc.postValidate}" />
</h:inputText>
</s:span>
</s:span>
<a4j:commandButton action="#{cc.attrs.saveAction}"
value="Save"
execute="input"
render="input" />
</s:validateAll>
</composite:implementation>
Here is the UIComponent
#FacesComponent("myInputComponent")
public class MyInputComponent extends UIInput implements NamingContainer {
static final String OTHER_INPUT_ID = "otherInput";
static final String OTHER_LABEL = "Other";
public void postValidate(ComponentSystemEvent event) {
UIInput input = (UIInput) event.getComponent();
if (input != null && OTHER_INPUT_ID.equals(input.getId())) {
UIInput selectInput = (UIInput) event.getComponent().findComponent("selectInput");;
boolean useOtherValue = false;
if (selectInput != null) {
Object value = selectInput.getValue();
useOtherValue = isUseOtherValue(value);
if (useOtherValue && isRequired()) {
String otherValue = (String) input.getValue();
if (StringUtils.emptyString(otherValue)) {
setInvalid(input);
showRequiredMessage(input);
}
}
}
}
}
private void setInvalid(UIInput input) {
input.setValid(false);
FacesContext.getCurrentInstance().validationFailed();
}
}
The component being used:
<my:myInput value="#{bean.value}" otherValue="#{bean.otherValue}" />
The setter on bean.value is still called after postValidate fails.
I've tried this on a similar component with only one input, and it works as expected when required value fails. It does not go into the setter.

Using backing bean value in javascript

<h:form prependId="false" id="vt_sel_form">
<p:panelGrid styleClass="center" columns="2">
<p:commandButton value="GO" oncomplete="alert(#{test.i})" actionListener="#{test.testfxn()}" update="#this"/>
</p:panelGrid>
</h:form>
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ViewScoped
#ManagedBean(name = "test")
public class TestClass implements Serializable {
int i ;
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
public void testfxn() {
setI(i++);
//i=i+10;
System.out.println("i" + i);
}
}
Here, alert(#{test.i}) is always displaying 0. How do i get backing bean value that changes when I click the commandButton. It works when I click button twice. It used to work fine when I used a4j:commandButton.
That's just because alert(#{test.i}); is evaluated when the commandButton is rendered. You can see the changed value by telling JSF to render the script again:
<h:commandButton value="click me" action="#{testClass.testfxn()}">
<f:ajax render="out" />
</h:commandButton>
<h:panelGroup id="out">
<h:outputScript>
alert(#{testClass.i});
</h:outputScript>
</h:panelGroup>
Unlike Richfaces where you can directly call javascript function, primefaces you need to have javascript function as:
function_name(xhr, status, args)
Using listed CommandButton as Example:
<p:commandButton value="GO" oncomplete="alert(#{test.i})" actionListener="#{test.testfxn()}" update="#this"/>
In function test.testfxn() we have:
public void testfxn(){
RequestContext reqCtx = RequestContext.getCurrentInstance();
i = i++;
reqCtx.addCallbackParam("i", i);
}
Here,In function call to backing bean from actionlistener the variables are added to RequestContext.
Now In javascript function:
function draw(xhr, status, args) {
console.log("We are into draw function");
jsonString = JSON.parse(args.i); //json variable is taken out from args variable.
console.log("The value of i "+ i);
}

Multiple instances of a composite component in a view?

I read many similar questions, but I cannot figure out how to solve my problem:
I wrote a composite component backed by a view-scoped, self-contained managed bean.
The component consists of an autocomplete textbox with a button that opens a dialog. The user can select an item either by name (autocomplete) or selecting a node in a tree (dialog).
The backing bean implements all the stuff needed (data access, tree-logics etc) and should expose the selected item (as a POJO).
Now I have 2 problems:
Due to the complexity of the tree management, selectedObj property is accessed by a getter and a setter that do some stuff in the bean: they are not simply accessing a class field. Now I'm passing the entire bean as an attribute. How can I just make the bean's selectedObj the "value" attribute of my composite component?
How can I use multiple instance of my component in the same view?
Here is an example of the component:
<cc:interface>
<cc:attribute name="bean" type="com.yankee.OUTreeBean" required="true"/>
<cc:attribute name="listener" method-signature="void listener()"/>
</cc:interface>
<cc:implementation>
<p:dialog id="#{cc.id}_dialog" widgetVar="_dlg" header="Select OU" modal="true" dynamic="true" >
<p:toolbar>
<!-- some buttons to refresh, expand, collapse etc. -->
</p:toolbar>
<p:tree id="#{cc.id}_tree" value="#{cc.attrs.bean.root}" var="node"
selectionMode="single"
selection="#{cc.attrs.bean.selectedNode}">
<p:ajax event="select" update="#form" listener="#{cc.attrs.listener}" oncomplete="if (!args.validationFailed) _dlg.hide()" />
<p:treeNode>
<h:outputText value="#{node.OU_NAME}" />
</p:treeNode>
</p:tree>
</p:dialog>
<p:autoComplete id="#{cc.id}_inner" value="#{cc.attrs.bean.selectedObj}" completeMethod="#{cc.attrs.bean.completeObj}"
var="obj" itemLabel="#{obj.OU_NAME}" itemValue="#{obj}"
forceSelection="true"
converter="ouConverter"
multiple="false"
minQueryLength="2">
<p:ajax event="itemSelect" listener="#{cc.attrs.listener}" update="#form"/>
</p:autoComplete>
<div style="float: right">
<p:commandButton id="bSearch" icon="ui-icon-search" onclick="_dlg.show()"/>
</div>
</cc:implementation>
The backing bean of the COMPONENT:
#ManagedBean
#ViewScoped
public class OUTreeBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<OU> data; // Data as plain list
protected TreeNode root; // root node of data as a tree
protected TreeNode selectedNode;
#PostConstruct
private void init() throws SQLException {
refreshData();
}
public OU getSelectedObj() {
if (selectedNode == null) {
return null;
}
return ((OU) selectedNode.getData());
}
public void setSelectedObj(OU ou) {
// Find the right tree node and do whatever needed
}
public TreeNode selectedNode getSelectedNode() {
// Blah blah
}
public void setSelectedNode(TreeNode selectedNode) {
// Blah blah
}
public List<OU> completeObj(String namePattern) {
// Autocomplete handler
}
public void refreshData() {
// Blah blah
}
// etc...
}
The using page excerpt:
<ism:selectOUTree id="cbSelectOu" bean="#{myBean.ouFilterBean}" listener="#{myBean.onOUChange}"/>
The backing bean of the PAGE:
#ManagedBean
#ViewScoped
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty("#{oUTreeBean}")
private OUTreeBean ouFilterBean;
public void onOUChange() throws SQLException {
// Blah blah
}
}
I had the same problem few days ago. Just like you I used ManagedBean as an object that should do the job. After some time I figured out that I should just create FacesComponent. I'm new in JSF so it wasn't that easy to find the solution but it solved all my problems. This is how does it work:
view.xhtml
<h:body>
<cc:interface componentType="playerComponent">
<cc:attribute name="playerId" required="true"/>
</cc:interface>
<cc:implementation>
<c:set var="inplaceId" value="inplace-#{cc.attrs.playerId}" />
<c:set var="outputId" value="output-#{cc.attrs.playerId}" />
<h:form id="form-#{cc.attrs.playerId}">
<p:inplace editor="false" widgetVar="#{inplaceId}">
<h:inputText value="#{cc.player.name}" id="outputId"/>
<p:commandButton onclick="#{inplaceId}.save()" action="#{cc.save}" update="#{outputId}" value="save" />
<p:commandButton onclick="#{inplaceId}.cancel()" update="#{outputId}" value="cancel" />
</p:inplace>
</h:form>
</cc:implementation>
</h:body>
PlayerComponent.java
#FacesComponent("playerComponent")
public class PlayerComponent extends UINamingContainer {
private Player player;
private void init() {
Object idObj = getAttributes().get("playerId");
if (idObj != null) {
// create player object
}
}
public void save() {
// save player object
}
public Player getPlayer() {
if (player == null) {
init();
}
return player
}
}
Player.java (entity)
public class Player {
private name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
As I wrote I'm new in JSF and probably player object should be created in different way (using #PostConstruct on in constructor?) but this work.

jsf2 template component with parameter

I have a jsf template page. In this template i would like to use component with parameter. Actually i would like to iterate over collection. This collection should be determined by parameters from particular page. Parameter name is selectedMenu. How can i use this in my bean?
<div id="notes">
selectedMenu: #{selectedMenu}
<h:form>
<h:inputHidden value="#{notatkaController.searchForm.kategoria}">
<f:param value="#{selectedMenu}" />
</h:inputHidden>
<ui:repeat value="#{notatkaController.items}" var="item" varStatus="iter">
<f:param value="#{selectedMenu}" />
<p class="q-title"><strong><h:outputText value="#{item.ntaData}" /></strong></p>
<p class="answer"><h:outputText value="#{item.ntaDane}" escape="false" /></p>
</ui:repeat>
<span>Moje notatki</span>
<textarea>Tu wpisz treść swojej notatki</textarea>
<span>[+] dodaj notatkę</span>
</h:form>
</div>
My bean:
#ManagedBean(name = "notatkaController")
#ViewScoped
public class NotatkaController extends AbstractController<Notatka> implements Serializable {
#EJB
private pl.alfaprojekt.model.session.NotatkaFacade ejbFacade;
private NotatkaSearchForm searchForm;
public DataModel getItems() {
if (items == null)
items = getPagination().createPageDataModel();
return items;
}
public PaginationHelper getPagination() {
if (pagination == null) {
if (paginationSize == null)
paginationSize = 10;
pagination = new PaginationHelper(paginationSize) {
#Override
public int getItemsCount() {
return getFacade().countByParam(getSearchForm());
}
#Override
public DataModel createPageDataModel() {
if (rapId == null)
return new ListDataModel(getFacade().findRangeByParam(getSearchForm(), new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
else {
Long uzyId = SessionUtil.getUser().getUzyId();
return new ListDataModel(convertToRaportWierszList(getFacade().findRangeByParam(getSearchForm(), new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}), uzyId));
}
}
};
}
return pagination;
}
}
I am not sure I understood the question but the question I answer is this:
I want to dynamically display something. I want to tell it what to display when the page gets accessed.
View:
You could then use the following:
<f:event listener="#{myBean.myMethod}" type="preRenderView" />
Bean:
public void myMethod(ComponentSystemEvent event){
//your logic here
}
With parameter:
<f:metadata>
<f:event listener="#{myBean.myMethod}" type="preRenderView" id="fevent"/>
<f:attribute name="myParam" value="#{mySecondBean.param)" />
</f:metadata>
And
public void myMethod(ComponentSystemEvent event){
String id = (String) event.getComponent().getAttributes().get("myParam");
}

PrimeFaces 3.0.M3 Cell Editor does not update value

I have read there, but i can't take edited value from primefaces datatable cellEditor, it gives me unedited value. i am using jpa.
xhtml page:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.prime.com.tr/ui"
template="/templates/masterLayout.xhtml">
<ui:define name="windowTitle">
learn
</ui:define>
<ui:define name="content">
<h:form>
<p:dataTable value="#{lesson.lessonValue}" var="l" style="width: 400px">
<p:ajax event="rowEdit" listener="#{lesson.onEditRow}"/>
<p:column headerText="Lessons" style="width: 300px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{l.lessonName}"/>
</f:facet>
<f:facet name="input">
<p:inputText value="#{l.lessonName}" style="width: 100%"/>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="Options">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
</ui:define>
</ui:composition>
lesson.java:
public class lesson implements Serializable {
private String name;
protected EntityLesson[] lessonList;
public String getName() { return name; }
public void setName(String newValue) { name = newValue; }
EntityManagerFactory emf = Persistence.createEntityManagerFactory("DefaultPU");
public EntityLesson[] getLessonValue() {
EntityManager em = emf.createEntityManager();
List<EntityLesson> result;
try {
EntityTransaction entr = em.getTransaction();
boolean committed = false;
entr.begin();
try {
Query query = em.createQuery("SELECT l FROM EntityLesson l");
result = query.getResultList();
entr.commit();
committed = true;
lessonList = new EntityLesson[result.size()];
lessonList = result.toArray(lessonList);
} finally {
if (!committed) entr.rollback();
}
} finally {
em.close();
}
return lessonList;
}
public void onEditRow(RowEditEvent event) {
EntityLesson editedLesson = (EntityLesson)event.getObject();//gives me unedited value
............................
............................
}
EntityLesson.java:
#Entity
#Table(name="lessonaaa")
public class EntityLesson implements Serializable {
#Id
#Column(name="Lesson_Id", nullable=false)
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int lessonId;
#Column(name="Lessson", nullable=false, length=65)
private String lessonName;
public int getLessonId() { return lessonId; }
public void setLessonId(int lessonId) { this.lessonId = lessonId; }
public String getLessonName() { return lessonName; }
public void setLesson (String lessonName) { this.lessonName = lessonName; }
}
The problem occurs because of the JSF lifecycle:
When your dataTable is displayed it executes the JPQL to retrieve the list of lessons. After that they are displayed.
Now you edit on entity and hit save, the edited entity in the list has now the new value.
But what happens next, is that the list is fetched another time and then the listener method is executed with the newly fetched enitiy.
You can solve the problem if you store the list of entities in a local attribute in the view bean and fill it in the post construct method (annotated by #PostContruct) and you have to make the view bean #SessionScoped. Then use this list for the datatable.
My problem is similar:
The 'dataTable' contains as 'value' a list of entities:
<p:dataTable id="category" var="category" value="#{categoriesBacking.categoriesListEdit}">
If I select one for edit, the object which is passed to the event contains the previously unmodified value. I observed that this is due to the fact that dataTable's value is a list. As a work-around (to be able to use the component) I added a 'filterBy' to any of the 'column'. If the dataTable will contain only one value, that value will be interpreted correctly by the passed event in the managed bean.
!!! The event's object will be the modified instance.
I also use:
<p:ajax event="rowEdit" update="#this" listener="#{categoriesBacking.onEditRow}" />
instead of dataTable's 'rowEditListener'.
Again, this is just a workaround.
I have almost exactly the same code except instead of using the <p:ajax> tag I am instead using the rowEditListener attribute of dataTable. Try this instead:
<p:dataTable ... rowEditListener="#{lesson.onEditRow}" ... >
...
This kind of problems are generally related to your backing bean. Your "lesson" class needs #ManagedBean (javax.faces.bean.ManagedBean) annotation. Simply add
#ManagedBean (name="YourBeanName")
#ViewScoped
just before public class lesson implements Serializable { line in your lesson.java

Resources