pass SelectOneMenu value to add function in JSF / Primefaces - java

i'm using primefaces schedule , when the dialog form pop up , i need to select data from SelectOneMenu and pass them to the add function in order to insert them into database
the problem is that sometimes it works great and i can insert them, but when i try to add another second insert i doesn't work again
can you check it out please ? i need to know if i'm doing this the wrong way because i can't find the problem.
Managedbean constructor :
#PostConstruct
public void init() {
Chauffeurs = new ArrayList<Chauffeur>();
ChauffeurDispo = new dao.gsVoyage().getChauffeursDesponible(Chauffeurs);
model = new DefaultScheduleModel();
vDao=new dao.gsVoyage();
voyage=new Voyage();
try {
listVoyage=vDao.getListVoyages();
}catch(Exception ex) {
ex.printStackTrace();
FacesContext.getCurrentInstance().addMessage(null,new FacesMessage(FacesMessage.SEVERITY_ERROR,"erreur","erreur no sql"));
}
for(Voyage v:listVoyage) {
DefaultScheduleEvent evt=new DefaultScheduleEvent();
evt.setEndDate(v.getDateV());
evt.setStartDate(v.getDateV());
evt.setDescription(v.getChauffeurBean().getMatricule());
evt.setData(v.getIdVoyage());
model.addEvent(evt);
}
}
the add function :
public void ajouter() {
try {
new dao.gsVoyage().addVoyage(dateV, autocar, chauffeur,chauffeur2,0);
DefaultScheduleEvent evt=new DefaultScheduleEvent();
evt.setEndDate(dateV);
evt.setStartDate(dateV);
evt.setDescription(chauffeur);
model.addEvent(evt);
} catch (Exception e) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error!", e.getMessage()));
}
voyage = new Voyage();
}
xhtml of SelectOneMenu :
<label>Chauffeur :</label><br/>
<h:selectOneMenu
value="#{scheduleJava8View.chauffeur}">
<f:selectItems
value="#{scheduleJava8View.chauffeurDispo}"
var="chauffeur" itemValue="#{chauffeur.matricule}"
itemLabel="#{chauffeur.nom}" />
</h:selectOneMenu>
this is how i display inserted data in xhtml
<label>Chauffeur:</label><br/>
<p:inputText value="#{scheduleJava8View.voyage.chauffeurBean.matricule}" />

Try changing your code to this
<h:selectOneMenu
onchange="submit()"
value="#{scheduleJava8View.chauffeur}">
This will make a call to
setChauffeur(Chauffeur c)
on your backed bean. Notice that in this case, you will need to define a converter since it is not a Java basic type (int, String,...).

Related

Reload ADF table after button click in a Fusion Web application

I recently started working on my first ADF project using JDeveloper 12c.
So, I have a Fusion Web Application that's connected to an Oracle database. On one of the jsf pages there are two ADF tables, that display data from the database. Below is a button that sends a "DELETE"-statement to the database to delete selected entries. For reasons both tables have to be refreshed after this (the deletion affects the shown entries of both tables).
After I was already really happy that the tables were displaying the correct data and the button did its thing too I quickly realized that if the database changes, the tables in the jsf page will not get refreshed automatically. I searched around the web a bit for a a good beginner level tutorial of how to refresh elements of a jsf page in an ADF Fusion application. Sadly I didn't found anything that gave me the key to it so far.
I found this article on the Oracle HQ page, but it also has the habit of using many propietary namings and is written in flowing text, so there is no code sample or snippet or similar in it, which made it difficult to follow for a rookie.
This is a snippet from my Managed java bean, where I store my button functionality:
public String update() {
getDBConnection c = new DBConnection();
Connection conn = c.getConn();
RowKeySet selectedEntries = getDetailTable().getSelectedRowKeys();
Iterator selectedEntryIter = selectedEntries.iterator();
DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
DCIteratorBinding entryIter = bindings.findIteratorBinding("my_iterator");
RowSetIterator rSIter = entryIter.getRowSetIterator();
try {
PreparedStatement pstmt1 = conn.prepareStatement("DELETE ...");
PreparedStatement pstmt2 = conn.prepareStatement("DELETE ...");
while(selectedEntryIter.hasNext()){
Key key = (Key)((List)selectedEntryIter.next()).get(0);
Row currentRow = rSIter.getRow(key);
BigDecimal barcode = (BigDecimal) currentRow.getAttribute("id");
BigDecimal field1 = (BigDecimal) currentRow.getAttribute("field1");
BigDecimal field2 = (BigDecimal) currentRow.getAttribute("field2");
pstmt1.setBigDecimal(1, id);
pstmt1.setBigDecimal(2, field1);
pstmt2.setBigDecimal(1, id);
pstmt2.setBigDecimal(2, field2);
pstmt1.executeUpdate();
pstmt2.executeUpdate();
}
conn.commit();
//i guess here i have to trigger to refresh the tables but I have pretty to no clue of how to do that
//where do I have to set the functionality? I read sth about creating another bean in the "session" package
//but somehow i have to access the jsf i want to have refreshed. Where do I create that connection?
//even a simple example or a good reference to a tutorial would be helpful for me
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return null;
}
Probably this question is a duplicate to an already existing one and i'm just too stupid to find it, but I will give it a try anyways. Thanks in advance!
In your case you can simply add a entryIter.executeQuery(); right after your conn.commit(); (You should also avoid running a direct sql delete and use the standard ADF BC DELETE https://o7planning.org/11489/create-update-and-delele-data-using-adf-form-in-adf-bc#a9769791)
But to answer the question title for future queries, below is an exemple of a simple refresh table button, easily reusable, that i usually add on my clients tables toolbar :
//in your jsff
<af:panelCollection id="pc" >
<f:facet name="menus"/>
<f:facet name="statusbar"/>
<f:facet name="toolbar">
<af:toolbar id="t1" flex="5">
<af:group id="g1">
<af:commandImageLink shortDesc="Reload" partialSubmit="true" actionListener="#{YOUR_SCOPE.YOUR_BEAN.refreshTable}"
icon="#{resource['images:YOUR_RELOAD_ICON.png']}">
<f:attribute name="tableIdToRefresh" value="YOUR_TABLE_ID"/>
</af:commandImageLink>
</af:group>
</af:toolbar>
</f:facet>
<af:table id="YOUR_TABLE_ID" value="#{bindings.YOUR_VO.collectionModel}" var="row" rows="#{bindings.YOUR_VO.rangeSize}"
selectedRowKeys="#{bindings.YOUR_VO.collectionModel.selectedRow}" selectionListener="#{bindings.YOUR_VO.collectionModel.makeCurrent}" rowSelection="single"
fetchSize="#{bindings.YOUR_VO.rangeSize}" filterModel="#{bindings.XxcnVieIntSearchVCQuery.queryDescriptor}"
queryListener="#{bindings.XxcnVieIntSearchVCQuery.processQuery}" varStatus="vs" >
<!-- COLUMNS -->
</af:table>
</af:panelCollection>
//in your bean #{YOUR_SCOPE.YOUR_BEAN.refreshTable}
public void refreshTable(ActionEvent actionEvent) {
//Get the attribute tableIdToRefresh value. I like to have it as a jsff attribute so i can easily reuse the button elsewhere
String tableToRefreshId = "" + ((RichCommandImageLink)actionEvent.getSource()).getAttributes().get("tableIdToRefresh");
if (sValeurCode != null) {
addPprToComponentById(tableToRefreshId);
//If it doesn't suffice (see below) you can use this :
//refreshTableIterator(tableToRefreshId);
}
}
public static void addPprToComponentById(String id) {
Object component = findComponentInRoot(id); //from the great JSFUtils library
if (component != null) {
AdfFacesContext.getCurrentInstance().addPartialTarget((UIComponent)component);
AdfFacesContext.getCurrentInstance().partialUpdateNotify((UIComponent)component);
}
}
/**
* Locate an UIComponent in view root with its component id. Use a recursive way to achieve this.
* #param id UIComponent id
* #return UIComponent object
*/
public static UIComponent findComponentInRoot(String id) {
UIComponent component = null;
if (id != null) {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext != null) {
UIComponent root = facesContext.getViewRoot();
if (root != null) {
component = findComponent(root, id);
}
}
}
return component;
}
You can also use this addPPR logic for other components.
If a simple ppr doesn't suffice. You can force the table query execution with those :
public static void refreshTableIterator(String tableId) {
RichTable table = findComponentInRoot(tableId);
DCIteratorBinding treeIterator = null;
if (table != null) {
treeIterator = getTableIterator(table);
if (treeIterator != null) {
RowSetIterator rsi = treeIterator.getRowSetIterator();
treeIterator.executeQuery();
rsi.closeRowSetIterator();
}
}
}
public static DCIteratorBinding getTableIterator(RichTable table) {
DCIteratorBinding treeIterator = null;
CollectionModel model = (CollectionModel)table.getValue();
if (model != null) {
JUCtrlHierBinding treeBinding = (JUCtrlHierBinding)model.getWrappedData();
if (treeBinding != null) {
treeIterator = treeBinding.getDCIteratorBinding();
}
}
return treeIterator;
}

JSF page is not showing the content

In system user can type a "URL", like "http://www.google.com" and this URL must be processed in SERVER and after the content is showed in XHTML page.
In my XHTML i have:
<h:form id="formNavegador" enctype="multipart/form-data">
<p:inputText value="#{navegadorMB.url}" required="true"
requiredMessage="A url é obrigatória"
type="Digite a url para navegar. Ex: http://www.google.com.br" />
<h:outputText value="#{navegadorMB.htmlContent}" escape="false"
id="htmlContent" />
<p:commandButton id="commandButtonProcessar" value="Ir"
update=":formNavegador:htmlContent" icon="ui-icon-play"
actionListener="#{navegadorMB.processaRequisicao}" />
</h:form>
So, when user type the URL and click in commandButton, the code bellow is processed:
public void processaRequisicao(ActionEvent event){
if (url.isEmpty()){
addErrorMessage("Você precisa digitar um endereço");
FacesContext.getCurrentInstance().validationFailed();
}else{
htmlContent = boPadrao.processaRequisicaoOnServer(url);
System.out.println(htmlContent);
}
}
In my method "processaRequisicaoOnServer" the URL is opened and all content is read, after the content of site is returned. See:
public String processaRequisicaoOnServer(String url) {
URL urlObj;
try {
urlObj = new URL(url.trim().toLowerCase());
BufferedReader conteudo = new BufferedReader(new InputStreamReader(urlObj.openStream()));
String linha = "";
StringBuffer sb = new StringBuffer();
while((linha = conteudo.readLine()) != null)
{
sb.append(linha);
}
return sb.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
throw new BOException(e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new BOException(e.getMessage());
}
}
So, the content of URL is showed in console because of "System.out.." but the h:outputText is not updated as i hope.
I can't see your entire bean here, but here are some things that I've noticed:
If this is your entire form, you don't need the enctype="multipart/form-data", so you can just remove it.
There is a strange type attribute in your first p:inputText. Didn't you mean title?
<p:inputText type="Digite a url para navegar. Ex: http://www.google.com.br" />
Also, you don't need to specify the parent of a component when the component is already a child of this parent, so you could change this:
<p:commandButton id="commandButtonProcessar" value="Ir" update=":formNavegador:htmlContent" icon="ui-icon-play" actionListener="#{navegadorMB.processaRequisicao}" />
to this:
<p:commandButton id="commandButtonProcessar" value="Ir" update="htmlContent" icon="ui-icon-play" actionListener="#{navegadorMB.processaRequisicao}" />
And you are calling an action listener and passing an ActionEvent, which you don't need to, so you could change this:
public void processaRequisicao(ActionEvent event) { ...
to this:
public void processaRequisicao() { ...
Furthermore, in order to test it all, you could go in steps, creating a mock method first and checking if things are working properly, and then adding your business stuff.
For instance, to test this you could change your processaRequisicao to something like:
public void processaRequisicaoMock() {
htmlContent = "Funcionou!";
}
And then call it, and check if the view is working properly. If it is, you can go on, adding the business layer and all.
I hope it helps.
Instead of
<p:commandButton id="commandButtonProcessar" value="Ir"
update=":formNavegador:htmlContent" icon="ui-icon-play"
actionListener="#{navegadorMB.processaRequisicao}" />
Try
<p:commandButton id="commandButtonProcessar" value="Ir"
update="htmlContent" icon="ui-icon-play"
actionListener="#{navegadorMB.processaRequisicao}" ajax="false"/>
Also, change your method to
public void processaRequisicao(){
if (url.isEmpty()){
addErrorMessage("Você precisa digitar um endereço");
FacesContext.getCurrentInstance().validationFailed();
}else{
htmlContent = boPadrao.processaRequisicaoOnServer(url);
System.out.println(htmlContent);
}
}

Primefaces selectOneMenu does not execute on change

I am writing a PrimeFaces application. I have the following code in my XHTML:
<p:selectOneMenu value="#{lottoCheckerBean.selectedPowerBallDrawingDate}">
<f:selectItems value="#{lottoCheckerBean.powerBallDrawingDates}" />
</p:selectOneMenu>
I am expecting the following code to be executed in my LottoCheckerBean when a value is selected:
public void setSelectedPowerBallDrawingDate(String selectedPowerBallDrawingDate) {
//get drawing
PowerBallDrawing currentDrawing = null;
for (int d = 0; d < powerBallDrawings.size(); d++) {
if (powerBallDrawings.get(d).getDrawingDate().equals(selectedPowerBallDrawingDate)) {
currentDrawing = powerBallDrawings.get(d);
break;
}
}
if (currentDrawing == null) {
try {
//create new drawing;
currentDrawing = new PowerBallDrawing(selectedPowerBallDrawingDate);
powerBallDrawings.add(currentDrawing);
Arrays.sort(powerBallDrawings.toArray());
} catch (Exception ex) {
//will not happen so ignore
}
}
this.selectedPowerBallDrawingDate = selectedPowerBallDrawingDate;
}
However, if I set a breakpoint at the beginning of the above method, the breakpoint is not reached.
What am I missing?
The code you expect to execute upon change will be called when you submit the form in which your selectOneMenu is placed. That is when the value from the selectOneMenu will be passed to your bean.
If you would want to perform something upon any other event, such as change, you need to enable ajax:
<p:selectOneMenu value="#{lottoCheckerBean.selectedPowerBallDrawingDate}" >
<f:selectItems value="#{lottoCheckerBean.powerBallDrawingDates}" />
<p:ajax event="change" listener="#{lottoCheckerBean.someMethod}" />
</p:selectOneMenu>
When value is changed in the backing bean, someMethod() will be called.
I would recommend you to use setSelectedPowerBallDrawingDate(String selectedPowerBallDrawingDate) only as a setter which sets the value, not to conatain any business logic at all. Then let the method you call from <p:ajax/> do the business logic.

how to keep the uploaded files in the form until submit it using jsf-2 and primefaces-3.4

I have form with many input fields plus primefaces component to upload multiple file "p:fileUpload" when I submit the form I can't get the uploaded files .. the manged bean is "RequestScoped" . So how can I get the uploaded files without making the manged bean View scope?
the upload method
public void upload(FileUploadEvent event) {
try {
FacesMessage msg = new FacesMessage("Success! ", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
// Do what you want with the file
String thumbnail = getDestination() + event.getFile().getFileName();
int index = thumbnail.lastIndexOf('.');
SystemFile systemFile = new SystemFile();
systemFile.setAccount(getActor().getAccount());
systemFile.setName(event.getFile().getFileName());
systemFile.setPath(getTalentPath());
systemFile.setFileType(FileUtil.checkFileType(thumbnail.substring(index + 1)));
if (systemFiles == null) {
systemFiles = new ArrayList<>();
}
systemFiles.add(systemFile);
copyFile(event.getFile().getFileName(), event.getFile().getInputstream());
} catch (IOException ex) {
SystemLogger.getLogger(getClass().getSimpleName()).error(null, ex);
}
}
primefaces component
<p:fileUpload label="#{TalentMessages.lbl_Select_File}" fileUploadListener="#{talentPropertyAction.upload}"
mode="advanced"
multiple="true"
uploadLabel="#{TalentMessages.lbl_upload_File}"
cancelLabel="#{TalentMessages.lbl_cancel_File}"
sizeLimit="2000000"
oncomplete="completeUploadFile(#{talentPropertyAction.talentId});"
/>
then the save function
#Setter
#Getter
private List<SystemFile> systemFiles;
try {
// save something else then save the files
if (systemFiles != null) {
System.out.println("Not Null" + systemFiles);
for (SystemFile systemFile : systemFiles) {
TalentPropertyFile talentPropertyFile = new TalentPropertyFile();
talentPropertyFile.setTalentProperty(talentProperty);
talentPropertyFile.setFile(systemFile);
getTalentService().save(getActor().getAccount(), talentPropertyFile);
}
} else {
System.out.println("Null");
}
} catch (InvalidParameter ex) {
SystemLogger.getLogger(getClass().getName()).error(null, ex);
}
So how can I get the uploaded files without making the manged bean View scope?
Just store the upload information immediately in a more permanent place than as a property of a request scoped bean which get garbaged by end of request-response anyway (note: every upload counts as a separate HTTP request).
public void upload(FileUploadEvent event) {
// Now, store on disk or in DB immediately. Do not assign to a property.
}
public void save() {
// Later, during submitting the form, just access them from there.
}
If you need some key to access them, consider storing the key in the session scope.

How to populate certain text field after selecting item from <h:selectOneMenu /> JSF 2.0

i want that, when user select item in a inputText field populates with data from database.
I have a select menu list:
<h:selectOneMenu id="blah" value="#{controller.selected.id}" title="#{bundle.CreateTitle_id}" >
<f:selectItems value="#{controller.listOfId()}" />
</h:selectOneMenu>
and let's say have input text like this:
<h:inputText value="In here we place value from backing bean"></h:inputText>
How can i make after selecting an item from a list(which holds the id) populate text field with other data from my backing bean(let's say a name).
Here is my backingBean:
#ManagedBean(name = "controller")
#SessionScoped
public class Bean implements Serializable {
private Catalog current;// here i'm holding int id, String name and other stuff...
private DataModel items = null;
#EJB
private probaSession.CatalogFacade ejbFacade;
private PaginationHelper pagination;
private int selectedItemIndex;
public KatalogController() {
}
public Katalog getSelected() {
if (current == null) {
current = new Catalog();
selectedItemIndex = -1;
}
return current;
}
private KatalogFacade getFacade() {
return ejbFacade;
}
public PaginationHelper getPagination() {
if (pagination == null) {
pagination = new PaginationHelper(10) {
#Override
public int getItemsCount() {
return getFacade().count();
}
#Override
public DataModel createPageDataModel() {
return new ListDataModel(getFacade().findRange(new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
}
};
}
return pagination;
}
//......
public ArrayList<Catalog> listOfId() {
ArrayList<Catalog> list=new ArrayList<Catalog>();
try{
String upit="select id from Catalog";
Statement st=connection.createStatement();
ResultSet rs=st.executeQuery(upit);
while(rs.next()) {
Katalog k=new Katalog();
k.setId(rs.getInt(1));
k.setName(rs.getString(2));
list.add(k);
}
disconnect();
}
catch (Exception ex) {
ex.printStackTrace();
}
return list;
}
and that's pretty much it.
I'm here if anything needs to explaining. It think it is easy(using ajax let's say) but i don't even know how to start doing it...
You must add an f:ajax (that is standard, many component library offer extended versions) to catch a change event in the inputText
<h:selectOneMenu id="blah" value="#{controller.selected.id}" title="#{bundle.CreateTitle_id}" >
<f:selectItems value="#{controller.listOfId()}" />
<f:ajax
event="change" <-- The event to capture. I believe that if not specified
there is a default event to capture from
each component (for inputText it would be "change")
render="myForm:foo" <-- Only repaint "blah"
listener="#{controller.myBlahListener}"
</h:selectOneMenu>
<h:inputText id="foo" value="#{controller.fooText}"/>
Your listener will read the new value in this.getSelected().getId(), and change the model so that controller.getFooText() returns the new value (the easiest way probably is this.setFooTest(this.getSelected().getId(), but that depends of your model.

Categories