CDI @ConversationScoped with AJAX

I have a pretty typical CRUD situation that I am struggling with, so I believe that I should misunderstand something. I put together a small demo application to better explain my problem. Below are two files of interest:

PersonView - Managed CDI Bean supporting JSF page

package example import java.io.Serializable; import java.util.List; import javax.enterprise.context.Conversation; import javax.enterprise.context.ConversationScoped; import javax.enterprise.inject.Produces; import javax.inject.Inject; import javax.inject.Named; @ConversationScoped @Named public class PersonView implements Serializable { private Person selectedPerson; @Inject private PersonService personService; @Inject private Conversation conversation; public PersonView() {} public List<Person> getPeople() { return personService.findAll(); } public void beginConversation() { if( conversation.isTransient() ) {conversation.begin();} } public void endConversation() { if( !conversation.isTransient() ) { conversation.end();} } public void createPerson() { beginConversation(); setSelectedPerson( new Person() ); } public void addPerson() { personService.addPerson( getSelectedPerson() ); endConversation(); } public void updatePerson() { personService.updatePerson( getSelectedPerson() ); } public Person getSelectedPerson() { return selectedPerson; } public void setSelectedPerson(Person selectedPerson) { this.selectedPerson = selectedPerson; } } 

index.xhtml - JSF page for managing people

 <?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:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui"> <h:head> <title>CRUD Example</title> </h:head> <h:body> <h:form prependId="false"> <p:dataTable var="p" value="#{personView.people}" id="person_table" rowKey="#{p.id}" selection="#{personView.selectedPerson}"> <p:column selectionMode="single"/> <p:column><f:facet name="header">ID</f:facet>#{p.id}<p:column> <p:column><f:facet name="header">Name</f:facet>#{p.name}</p:column> <f:facet name="footer"> <p:commandButton value="Create Person" onclick="create_dialog.show();" actionListener="#{personView.createPerson}"/> <p:commandButton value="Edit Person" onclick="edit_dialog.show();" update="edit_panel"/> </f:facet> </p:dataTable> </h:form> <p:dialog header="Create Person" id="create_dialog" widgetVar="create_dialog" modal="true" width="750" height="300"> <h:form prependId="false"> <p:panel id="create_panel"> <p>Name: <p:inputText value="#{personView.selectedPerson.name}" required="true"/></p> <p><p:commandButton value="Add" actionListener="#{personView.addPerson}" oncomplete="create_dialog.hide();" update="person_table" /></p> </p:panel> </h:form> </p:dialog> </h:body> 

The index page shows the user a data table containing all the people the system knows about. Then click the "Create Person" button at the bottom of the table. I checked that this correctly calls the createPerson method, and the conversation seems to be starting. Then create_dialog is displayed, where the user can enter a name. The problem occurs when the user clicks the Add button. JSF tries to save the username, but the selectedPerson variable is now null, so it does not work with a NullPointerException.

I understand that this is not the usual way to create objects, but it makes sense in my current application, as I can guess some of the values ​​of the new Person. It is also great for the way I would like to edit.

So my question (s): why is the conversation not spreading? PersonView Bean is always in the request area. I read about @ViewScoped in JSF2, but I would rather stick with CDI if possible. From what I read, I think the problem is the inability to pass the CID name with the request, but I don’t understand how to do this with AJAX.

The only solution I came up with is to bring the PersonView into the session, but it looks like a huge kludge. e

+4
source share
2 answers

The only way I got this is to use @ViewAccessScoped in MyDaces CODI . CDI allows extensibility, so all you have to do is include the CODI flag files in the application. This works even if you use Mojarra and not MyFaces.

So, if you want to use CDI annotations, this is my recommendation. I tried for a while to use the ConversationScoped annotation, but I just couldn't get it to work conveniently. When I started using CODI, all my problems disappeared.

+4
source

It looks like you're using PrimeFaces, I'm not sure how to make an ajax call using Primefaces, so I will show you how to do it with standard JSF 2.0

First of all, when using AJAX, you MUST pass cid with every AJAX request. Try adding the following to your ConversationScope Managed Bean (you need to somehow pass the cid to the view - index.xhtml, then each subsequent AJAX call will send the same cid back to the server):

 @Named @ConversationScoped public class PersonView implements Serializable { public List<Person> getPeople() { return personService.findAll(); } @Inject private Conversation conversation; //Start the conversation once the //bean is created and all injection is done on the bean //I typically use this in the case of AJAX @PostContruct public void beginConversation() { if( conversation.isTransient() ) { conversation.begin(); } } public void endConversation() { if( !conversation.isTransient() ) { conversation.end(); } } // This will be used in the view (index.xhtml) public String getConversationId() { return conversation.getId(); } public void createPerson() { setSelectedPerson( new Person() ); } public void addPerson() { personService.addPerson( getSelectedPerson() ); endConversation(); // beginConversation(); //might need to start a new conversation once old one is done } } 

Now, in your opinion, you will usually do the following:

 <h:commandButton action="#{personView.createPerson}" value="Create Person"> <!-- passing the cid --> <f:param name="cid" value="#{personView.conversationId}" /> <f:ajax execute="@form" /> </h:commandButton> <h:commandButton action="#{personView.addPerson}" value="Add"> <!-- passing the cid --> <f:param name="cid" value="#{personView.conversationId}" /> <f:ajax execute="@form" render=":person_table" /> </h:commandButton> 

This works until all subsequent AJAX calls. If you start confusing it with regular calls, the conversation will be lost. On the other hand, it was a list of non-AJAX calls that you make, cid will be automatically sent to you

0
source

Source: https://habr.com/ru/post/1380155/


All Articles