4
votes

I have a DTO which has a list. I want to add new rows to datatable when user clicks add button. But when I click add the dto i.e constructor is called and value is initialized and list size is 0. The bean is conversation scoped. Should I start and end conversation for same view while using conversation scoped bean? I am using same bean for edit and it is working well. How to solve initialization problem while using richfaces 4 and jsf 2 and ajax.

View:

                    <rich:panel id ="dataPnl">
                        <rich:dataTable value="#{legendbean.legendDTO.list}" var="legend" style="width:100%">

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="SN"/>
                                </f:facet>
                                <h:inputText value="#{legend.sn}"/>
                            </rich:column>

                            <rich:column>
                                <f:facet name="header">
                                    <h:outputText value="Description"/>
                                </f:facet>
                                <h:inputText value="#{legend.desc}"/>
                            </rich:column>


                            <rich:column>
                                <a4j:commandLink value="Add" actionListener="#{legendbean.addLegendRange()}" render="nisForm:dataPnl"/>
                                <h:outputText value=" / "/>
                                <a4j:commandLink value="Remove" actionListener="#{legendbean.removeLegendRange(legend)}" render="nisForm:dataPnl"/>
                            </rich:column>

                        </rich:dataTable>
                    </rich:panel>                 

Bean :

@Named("legendbean")
@ConversationScoped
public class LegendController implements Serializable {

    LegendDTO legendDTO = new LegendDTO();
    String selectedLegend;
    boolean edit;
    @Inject
    private Conversation conversation;

    public boolean isEdit() {
        return edit;
    }

    public void setEdit(boolean edit) {
        this.edit = edit;
    }

    public LegendController() {
        Logger.getLogger(LegendController.class.getName()).warning("The value of Edit is : " + edit);
        if (!edit) {
            legendDTO.getList().add(new Legend());
            Logger.getLogger(LegendController.class.getName()).warning("The size of list" + legendDTO.getList().size());
        }
    }

    public LegendDTO getLegendDTO() {
        return legendDTO;
    }

    public void setLegendDTO(LegendDTO legendDTO) {
        this.legendDTO = legendDTO;
    }

    public void addLegendRange() {
        Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
        legendDTO.getList().add(new Legend());
        Logger.getLogger(LegendController.class.getName()).warning("List Size " + legendDTO.getList().size());
    }

    public void removeLegendRange(Legend legend) {
        if (legendDTO.getList().size() != 1) {
            legendDTO.getList().remove(legend);
        }
    }

    public String saveLegend() {
        Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
        LegendDAO dao = new LegendDAO();
        if (dao.addLegend(legendDTO, edit)) {
            if (edit) {
                conversation.end();
                edit = false;
                Logger.getLogger(LegendController.class.getName()).warning("Save Legend Edit" + edit);
                return "VIEWLEGEND";
            } else {
                legendDTO = new LegendDTO();
                legendDTO.getList().add(new Legend());              
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Saved !"));
                return "";
            }
        } else {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Could Not Save Confim if you have already defined Legend " + legendDTO.getLegendName() + "!"));
            return "";
        }
    }

    public List<LegendDTO> getLegends() {
        LegendDAO dao = new LegendDAO();
        return dao.getLegendDTO();
    }

    //All function from here are for legend  delete
    public void deleteLegendType(LegendDTO dto) {
        LegendDAO dao = new LegendDAO();
        if (dao.deleteLegendType(dto.getLegendName())) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted !"));
        } else {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Deleted Error !"));
        }
    }

    //All function from here is to legend edit
    public String editLegendType(LegendDTO dto) {
        conversation.begin();
        edit = true;
        legendDTO = dto;
        LegendDAO dao = new LegendDAO();
        dto.getList().clear();
        try {
            List<Legend> legends = dao.getDetailForEditLegend(dto.getLegendName());
            dto.setList(legends);
        } catch (SQLException ex) {
            Logger.getLogger(LegendController.class.getName()).warning("SQL EXception has occoured");
        }
        Logger.getLogger(LegendController.class.getName()).warning("The size of list" + dto.getList().size());
        return "addLegend";
    }

    public String cancel() {
        conversation.end();
        return "VIEWLEGEND";
    }
}
2
Are you using RichFaces 2? Maybe you mean JSF 2 and RichFaces 4.xLuiggi Mendoza
@LuiggiMendoza yes JSF 2 richfaces 4.x any problem with using those combination??kinkajou
No, just clarifying the terms in your post.Luiggi Mendoza

2 Answers

2
votes

Yes, you need to start a long-running conversation in order to make your conversation (and conversation scoped beans) span multiple requests. Otherwise conversation gets killed at the end of a JSF request (conversation is transient by default: refer to ConversationScoped javadoc).

Also a common solution in such cases as yours is to use ViewScoped beans, but the annotation is JSF2 specific and is not presented in CDI (you can port it to CDI or use seam-faces module, more details: http://www.verborgh.be/articles/2010/01/06/porting-the-viewscoped-jsf-annotation-to-cdi/).

2
votes

If you're not constrained to using CDI/Seam annotations, you can change your bean to use @ManagedBean(name="legendbean") from the javax.faces.bean.ManagedBean package and then use a @ViewScoped annotation on your class that guarantees that as long as the user is on the same page, you'll be using the same instance of the managed bean. Nothing else needs to change at all with your setup, all @Injects will work as normal. To initialize the backing legendDTO.list, annotate a method in your ViewScoped JSF bean with @PostConstruct JSF annotation and put the list population logic in there. You can safely add/remove to the list without it being re-initialized to empty. But you must remember to commit the changes to this list back to the database.

Just a thought, you might want to show a popup that will allow your users confirm they want to delete anything from your db, as safe practice. Cheers