I'm new to java and primefaces. I am using autocomplete within datatable.
With the autocomplete I select the product, I use ajax, to update the price of the product in "MovtosBean.UpdatePrice".The "item" object in MovtosBean.UpdatePrice, returns the "null" value that the selected product should return.
Where do I have the error?
I appreciate your help.
Thanks.
package com.siptec.sm_fact.classes;
import com.siptec.sm_fact.entities.Productos;
import com.siptec.smfact.entities.facade.ProductosFacadeLocal;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.enterprise.inject.New;
import javax.faces.application.FacesMessage;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.primefaces.component.datatable.DataTable;
import org.primefaces.event.SelectEvent;
#Named
#ViewScoped
public class MovtosBean implements Serializable{
public void UpdatePrecio(SelectEvent e){
Object item = e.getObject();
FacesMessage msg = new FacesMessage("Selected", "Item" + item);
// Productos p = ((Productos) e.getObject());
// p.getPrecio();
}
}
<h:body>
<h:form>
<p:dataTable value="#{movtosBean.lstMovimientos}" var="mov" editMode="cell" rowKey="#{mov.id}"
widgetVar="movProd" editable="true" rowIndexVar="rowIndex">
<p:column headerText="Id">
<h:outputText value="#{mov.id}"/>
</p:column>
<p:column headerText="Producto">
<h:outputLabel for="idprod" />
<p:inplace id="idprod" label="Ingrese productos" effectSpeed="fast" event="click">
<p:autoComplete
id="mProductos"
value="#{movtosBean.lstproductos}"
completeMethod="#{movtosBean.CargaSugerencias(query)}"
var="pro"
itemValue="#{pro}"
itemLabel="#{pro.descripProducto}"
converter="omnifaces.SelectItemsConverter"
dropdown="false">
<p:column>
#{pro.codProducto} - #{pro.descripProducto}
</p:column>
<p:ajax event="itemSelect" listener="#{movtosBean.UpdatePrecio}"
update="mPrecio">
</p:ajax>
</p:autoComplete>
</p:inplace>
</p:column>
</p:dataTable>
</h:form>
</h:body>
</html>
converter="omnifaces.SelectItemsConverter" looks up items in component's f:selectItems. That's not p:autoComplete - it doesn't have f:selectItems. You need to provide a different converter (seems like you have entities here, so create a converter that does EntityManager#find or getReference). Or no converter, if you just want strings.
Related
Please see the image below.
image
Those images show how things work with my current code. When I delete the last panel and push the update button, all the panels disappear somehow.
It works well when I do the same with the rest of the panels.
If anyone knows how to solve this problems, it would be a great help.
Thanks in advance.
I've attatched the code below (just in case):
【xhtml】
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head></h:head>
<h:body>
<h:form>
<ui:repeat value="#{newapp001.list}" var="item" >
<p:panel header="#{item}" closable="true" >
<p>my information</p>
</p:panel>
</ui:repeat>
<p:commandButton value="Update" update="#form" />
</h:form>
</h:body>
</html>
【ManagedBean】
package sample;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
#Named("newapp001")
#SessionScoped
public class NewApp001 implements Serializable
{
private static final long serialVersionUID = 2610647621325923945L;
private List<String> list;
public NewApp001()
{
this.list = new ArrayList<>();
this.list.add("aaa");
this.list.add("bbb");
this.list.add("ccc");
this.list.add("ddd");
return;
}
public List<String> getList()
{
return this.list;
}
}
When you press the button, the panels' visibility state gets submitted. It's definitely a PF bug, that the last rendered panel's state affects all panels.
Since you don't seem to be interested in tracking the visibility state, the easiest fix would be to not process the panels, thus not storing the visibility state on the server:
<p:commandButton value="Update" process="#this" update="#form" />
How could I update a single row in a p:datatable when using AJAX?
I don't want to update the whole datatable because it has a lot of rows and it's going to take some time..
My layout:
<h:form id="visitForm">
<p:dataTable id="visitTable" var="visit" value="#{visitBean.findAllVisits()}">
<p:column headerText="${msgs['email']}"
<h:outputText value="#{visit.contactDetail.email}"/>
</p:column>
<p:column headerText="${msgs['clearance']}" id="clearance">
<p:commandButton value="${msgs['clearance.ok']}" actionListener="#{visitBean.makeClearanceNotOk(visit)}"/>
</p:column>
</p:dataTable>
</h:form>
I've tried out some things like update = "clearance" etc but it doesn't seem to work.
I'm using JSF 2.1 and Primefaces 5.2
You can use #row(n) search expression which does just that - it updates the nth row in a table. In order to update the current row, you need to pass row index as an argument. Set rowIndexVar="rowIdx" attribute on <p:dataTable> and then:
<p:commandButton ... update="#form:visitTable:#row(#{rowIdx})" />
Not sure if I'm late for the party but let me give my 5 cents on this subject on how to update content of a row using just plain ajax features from PrimeFaces.
1) Partial update: My first approach to update something in a specific row using PF is not exactly update the whole row, but update the regions of interest inside the row. This can be achieved by just defining the holding panels and updating them. For example:
<h:form id="testForm">
<p:dataTable id="myEntityTable" var="myEntity" value="#{myController.allEntities}">
<p:column headerText="id">
<h:outputText value="#{myEntity.id}"/>
</p:column>
<p:column headerText="last update">
<p:outputPanel id="lastUpdatePanel">
<h:outputText value="#{myEntity.lastUpdate}">
<f:convertDateTime pattern="HH:mm:ss" type="date" />
</h:outputText>
</p:outputPanel>
</p:column>
<p:column headerText="counter">
<p:outputPanel id="counterPanel">
<h:outputText value="#{myEntity.counter}"/>
</p:outputPanel>
</p:column>
<p:column headerText="increment">
<p:commandButton value="+"
actionListener="#{myController.increment(myEntity)}"
update="counterPanel, lastUpdatePanel"/>
</p:column>
</p:dataTable>
</h:form>
The trick is to update the target panels (in this example the fragment update="counterPanel, lastUpdatePanel"). This results in something like the following image:
2) Actually updating the row: Very often the previous approach works fine enough. However, if it is really needed to update the row one can follow the advice given in one of the previous answers and use the #row keyword:
<h:form id="testForm">
<p:dataTable id="myEntityTable" var="myEntity" value="#{myController.allEntities}" rowIndexVar="rowIndex">
<p:column headerText="id">
<h:outputText value="#{myEntity.id}"/>
</p:column>
<p:column headerText="last update 1">
<p:outputPanel>
<h:outputText value="#{myEntity.lastUpdate}">
<f:convertDateTime pattern="HH:mm:ss" type="date" />
</h:outputText>
</p:outputPanel>
</p:column>
<p:column headerText="last update 2">
<h:outputText value="#{myEntity.lastUpdate}">
<f:convertDateTime pattern="HH:mm:ss" type="date" />
</h:outputText>
</p:column>
<p:column headerText="counter">
<p:outputPanel>
<h:outputText value="#{myEntity.counter}"/>
</p:outputPanel>
</p:column>
<p:column headerText="increment">
<p:commandButton value="+"
actionListener="#{myController.increment(myEntity)}"
update="#form:myEntityTable:#row(#{rowIndex})"/>
</p:column>
</p:dataTable>
</h:form>
The trick is to hold each content from the columns inside a p:outputPanel and let update="#form:myEntityTable:#row(#{rowIndex})" make the job. I consciously leave the "last update 2" column without an outputPanel in order to illustrate this point:
Hence, whereas the columns "last update 1" and "counter" actually update after a click in "+" the "last update 2" column keeps unchanged. So, if you need to update a content, wrap up it with an outputPanel. It is noteworthy as well that the outputPanels holding each column content don't need an explicit id (you can add one if you want).
In the sake of completeness, in these examples I have used PF 6.2. The backbean is pretty straightforward:
package myprefferedpackage;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class MyController {
private List<MyEntity> entities;
#PostConstruct
public void init() {
this.entities = new ArrayList<MyEntity>(10);
for(int i = 0; i < 10; ++i) {
this.entities.add(new MyEntity(i));
}
}
public List<MyEntity> getAllEntities() {
return entities;
}
public void increment(MyEntity myEntity) {
myEntity.increment();
}
public class MyEntity {
private int id;
private int counter;
private Date lastUpdate;
public MyEntity(int id) {
this.id = id;
this.counter = 0;
this.lastUpdate = new Date();
}
public void increment() {
this.counter++;
this.lastUpdate = new Date();
}
public int getId() {
return id;
}
public int getCounter() {
return counter;
}
public Date getLastUpdate() {
return lastUpdate;
}
}
}
Either use the 'ajax' functionality of a utility library like OmniFaces or be creative with the PrimeFaces Selectors.
In both cases you need to get access to the e.g. the 'current' row or rowId. But since that you have the buttons IN the row, that should not be a problem. I unfortunately don't have the time to create examples for you
I try with uptate = "#parent:componentAnotherColumn" and works. Only update the same row
<p:column>
<p:selectBooleanCheckbox value="#{atributoVar.booleanValue}">
<p:ajax process="#this" update="#parent:componentAnotherColumn"/>
</p:selectBooleanCheckbox>
</p:column>
<p:column>
<p:selectBooleanCheckbox id="componentAnotherColumn" value="#{!atributoVar.booleanValue}"/>
</p:column>
The technical Context
We are developing a J2E application with JSF 2.2 and IBM WAS 8.5.5.
The problem
We have developed a screen in order to load different forms (12 differents forms which include Ajax and other subform...). We want to be able to load dynamically the form in a modal box in Ajax using "ui:include" tag.
Unfortunately, the actions associated to those forms generated dynamically are not executed.
The questions
Do somebody had this problem earlier ?
Do you have some clue to solve the problem ?
Do you know an alternative to load dynamic forms in the same page ?
The code
We built a simple example showing the problem we have.
The main page (fragment)
<ui:composition template="/WEB-INF/templates/globalLayout.xhtml">
<ui:param name="context" value="publication"/>
<ui:define name="content">
<h:form>
<h:commandLink value="EDIT1"
action="#{test.edit()}" layout="block" >
</h:commandLink>
<h:commandLink value="EDIT2"
action="#{test.edit2()}" layout="block" >
</h:commandLink>
<ui:include src="#{test.page}"/>
</h:form>
</ui:define>
</ui:composition>
The subpage 1 (fragment)
<h:outputText value="Page 1 "></h:outputText>
<h:commandLink value="EDIT1" action="#{test.edit()}" layout="block" >
</h:commandLink>
<h:commandLink value="EDIT2" action="#{test.edit2()}" layout="block" >
</h:commandLink>
The subpage 2 (fragment)
<h:outputText value="Page 2 "></h:outputText>
<h:commandLink value="EDIT1" action="#{test.edit()}" layout="block" >
</h:commandLink>
<h:commandLink value="EDIT2" action="#{test.edit2()}" layout="block" >
</h:commandLink>
The managed Bean
package com.myapp;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean(name = "test")
#ViewScoped
public class TestManagedBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3750906342500909173L;
private String page;
public void edit() {
page = "page.xhtml";
}
public void edit2() {
page = "page2.xhtml";
}
public String getPage() {
return page;
}
public void setPage(String page) {
this.page = page;
}
}
Note
Using the "ui:fragment" element is not useable. For us, it take nearly one minute to generated the page whereas with full ajax it should takes nearly 2,3 seconds.
So the example below is not working for us.
<ui:fragment rendered="#{index.page eq 'page2'}">
<ui:include src="page2.xhtml"/>
</ui:fragment>
Try using <ui:decorate template="#{test.page}"/> instead.
I have a ViewScoped CDI bean (javax.faces.view.ViewScoped). It reconstructs (calls a #PostConstruct method) when an ajax render its parent element. What should I do?
Bean:
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
#Named("test")
#ViewScoped
public class TestBean implements Serializable {
private List<Integer> items;
#PostConstruct
private void postConstruct() {
Logger.getLogger("asd").log(Level.INFO, "construct");
items = new ArrayList<Integer>();
items.add(0);
items.add(1);
items.add(3);
items.add(4);
items.add(7);
items.add(10);
}
public List<Integer> getItems() {
return items;
}
public void setItems(List<Integer> items) {
this.items = items;
}
}
View:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough">
<h:head>
<title>Simple JSF Facelets page</title>
</h:head>
<h:body>
<h:form>
<h:commandButton value="No reconstructing">
<f:ajax render=":panel" />
</h:commandButton>
</h:form>
<h:panelGrid id="panel">
<h:panelGroup>
<h:form>
<h:commandButton value="Strange reconstructing occurs">
<f:ajax render=":panel" />
</h:commandButton>
</h:form>
<ui:repeat value="#{test.items}" var="i">
#{i}
</ui:repeat>
</h:panelGroup>
</h:panelGrid>
</h:body>
</html>
Firstly click on the first button.
I'm working on a JSF 2.0 form, I have a managedbean with 2 fields
import java.util.Date;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
#ManagedBean
#RequestScoped
public class StackOverflow {
private Date firstDate;
private Date secondDate;
public void submit(){
//validate here and show error on form
}
}
and the xhtml like:
<h:inputText value="#{stackOverflow.firstDate}">
<f:convertDateTime pattern="d/M/yyyy" />
</h:inputText>
<h:inputText value="#{stackOverflow.secondDate}">
<f:convertDateTime pattern="d/M/yyyy" />
</h:inputText>
<h:commandLink action="#{stackOverflow.submit}">
<span>Submit</span>
</h:commandLink>
I want to validate the first and second date that the second date is not before the first date
Here's one of the ways:
<h:messages globalOnly="true"/>
<h:form>
<h:inputText value="#{stackOverflow.firstDate}" binding="#{firstDate}">
<f:convertDateTime pattern="d/M/yyyy" />
</h:inputText>
<h:inputText value="#{stackOverflow.secondDate}" validator="dateValidator">
<f:attribute name="firstDate" value="#{firstDate}" />
<f:convertDateTime pattern="d/M/yyyy" />
</h:inputText>
<h:commandButton value="Submit" action="#{stackOverflow.submit}"/>
</h:form>
with
#FacesValidator(value="dateValidator")
public class DateValidator implements Validator {
#Override
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
UIInput sd = (UIInput)component.getAttributes().get("firstDate");
Date firstDate = (Date)sd.getValue();
Date secondDate = (Date)value;
if(!firstDate.before(secondDate)){
FacesMessage msg = new FacesMessage("Entered dates are invalid: first date must be before second date");
throw new ValidatorException(msg);
}
}
}