camicase camicase - 1 month ago 20
Ajax Question

Primefaces datatable duplicates data on deletion

im using hibernate 4, spring 4, lucene 3, primefaces 5, java 7.

I got a data table, which data is populated on the baking bean, the idea with the table is that it shows me some uncategorized words, and lets me categorizate them.

an example of the initial table looks normal for example

1 2 3 4 5

here is my page

<html 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.org/ui">

<h:head>

</h:head>

<h:form id="form">
<p:growl id="msgs" showDetail="true" life="2000" />

<p:dataTable id="words" var="word"
value="#{wordCatalogatorController.unknownWords}" editable="true"
style="margin-bottom:20px">
<f:facet name="header">Row Editing</f:facet>

<p:ajax event="rowEdit"
listener="#{wordCatalogatorController.onRowEdit}" update=":form:msgs" />
<p:ajax event="rowEditCancel"
listener="#{wordCatalogatorController.onRowCancel}" update=":form:msgs" />

<p:column headerText="Palabra">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{word.word}" />
</f:facet>
<f:facet name="input">
<h:outputText value="#{word.word}" />
</f:facet>
</p:cellEditor>
</p:column>

<p:column headerText="Tipo Palabra">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{word.wordType}" />
</f:facet>
<f:facet name="input">
<h:selectOneMenu value="#{word.wordType}" style="width:100%"
converter="#{wordTypeConverter}">
<f:selectItems value="#{wordCatalogatorController.wordTypes}"
var="man" itemLabel="#{man.wordType}" itemValue="#{man}" />
</h:selectOneMenu>
</f:facet>
</p:cellEditor>
</p:column>

<p:column style="width:32px">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
</html>


the bean for this is:

@Controller
@Transactional
public class WordCatalogatorController {

private List<Word> unknownWords = new ArrayList<Word>();

private List<WordType> wordTypes = new ArrayList<WordType>();

public WordCatalogatorController(){
//inicializamos palabras desconocidas y tipos de palabras!
for(int i = 0 ; i < 6 ; i++){
unknownWords.add(new Word("" + i));
}

for(int i = 0 ; i < 4 ; i++){
wordTypes.add(new WordType("" + i));
}

}

public void onRowEdit(RowEditEvent event) {
Word currentWord = (Word) event.getObject();

unknownWords.remove(currentWord);
}

public void onRowCancel(RowEditEvent event) {
FacesMessage msg = new FacesMessage("Edit Cancelled",
((Word) event.getObject()).getWord());
FacesContext.getCurrentInstance().addMessage(null, msg);
}

public void onCellEdit(CellEditEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();

if (newValue != null && !newValue.equals(oldValue)) {
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO,
"Cell Changed", "Old: " + oldValue + ", New:" + newValue);
FacesContext.getCurrentInstance().addMessage(null, msg);
}
}


then after editing and saving the first row (1) the datatables updates with 1 2 2 3 4 5

Any ideas will be really apreciated!

here comes the code for pojo clases

@Entity
@Table(name="Word")
@Indexed
@AnalyzerDef(name = "searchtokenanalyzer",tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = StandardFilterFactory.class),
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = StopFilterFactory.class,params = {
@Parameter(name = "ignoreCase", value = "true") }) })
@Analyzer(definition = "searchtokenanalyzer")
public class Word {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long wordId;

@Column(name="word")
@Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
@Analyzer(definition="searchtokenanalyzer")
private String word;

@ManyToMany(mappedBy="words")
private Collection<Danger> dangers = new ArrayList<Danger>();

@ManyToMany(mappedBy="words")
private Collection<Risk> risks = new ArrayList<Risk>();

@ManyToMany(mappedBy="words")
private Collection<Control> controls = new ArrayList<Control>();

@ManyToOne
@JoinColumn(name = "wordTypeId")
private WordType wordType;

public Word(String word, WordType wordType) {
super();
this.word = word;
this.wordType = wordType;
}

public Word(String word) {
super();
this.word = word;
}



@Override
public boolean equals(Object obj) {
if(obj instanceof Word){
return ((Word)obj).getWord().equalsIgnoreCase(this.getWord());
}else{
return false;
}
}

public Word() {
super();

}

public long getWordId() {
return wordId;
}

public void setWordId(long wordId) {
this.wordId = wordId;
}



@Entity
@Table(name = "WordType")
@Indexed
public class WordType {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long wordTypeId;

@Column(name = "wordType")
@Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO)
@Analyzer(definition = "searchtokenanalyzer")
private String wordType;

@Column(name = "description")
private String description;

@OneToMany(mappedBy = "wordType")
private Set<Word> words;

@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if (!(obj instanceof WordType)) {
return false;
} else {
WordType extenalWT = (WordType) obj;
if (this.wordType.equalsIgnoreCase(extenalWT.getWordType())
&& this.wordTypeId == extenalWT.getWordTypeId()) {
return true;
} else {
return false;
}
}
}

public WordType() {

}

public WordType(String wordType) {
this.wordType = wordType;
}

public long getWordTypeId() {
return wordTypeId;
}

public void setWordTypeId(long wordTypeId) {
this.wordTypeId = wordTypeId;
}

public String getWordType() {
return wordType;
}

public void setWordType(String wordType) {
this.wordType = wordType;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public Set<Word> getWords() {
return words;
}

public void setWords(Set<Word> words) {
this.words = words;
}

@Override
public String toString() {
return wordType;
}

}

Answer

Finally the best solution was to implement the select event for the data table, and in the event have a dialog to pick the option, then refresh the table, this is the final xhtml

<html 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.org/ui">

<h:head>

</h:head>

<h:body>


    <h:form id="myForm">
        <p:growl id="msgs" showDetail="true" life="2000" />


        <p:panel header="Sale Item" style="width: 400px;">

            <h:panelGrid columns="2" cellpadding="5">
                <p:outputLabel value="Texto" for="acSimple" />
                <p:autoComplete id="acSimple"
                    value="#{wordCatalogatorController.texto}"
                    completeMethod="#{wordCatalogatorController.completeText}"
                    binding="#{wordCatalogatorController.autoCompleteText}" />

                <p:commandButton value="Guardar actividad" id="save"
                    update=":myForm:msgs words"
                    binding="#{wordCatalogatorController.saveButton}"
                    actionListener="#{wordCatalogatorController.saveActivity}"
                    styleClass="ui-priority-primary" process="@this" />
            </h:panelGrid>

            <p:dataTable id="words" widgetVar="words" var="word"
                value="#{wordCatalogatorController.unknownWords}" editable="true"
                style="margin-bottom:20px" rowKey="#{word.word}"
                selection="#{wordCatalogatorController.selectedWord}"
                selectionMode="single" editMode="row">

                <p:ajax event="rowSelect"
                    listener="#{wordCatalogatorController.changeClient}"
                    oncomplete="PF('activityDialog').show()"
                    update=":myForm:activityDialog" />

                <f:facet name="header">Edicion de palabras</f:facet>

                <p:column headerText="Palabra">
                    <h:outputText value="#{word.word}" />
                </p:column>

                <p:column headerText="Edicion">
                    <h:outputText value="Presione para catalogar la palabra" />
                </p:column>
            </p:dataTable>

        </p:panel>



        <p:dialog id="activityDialog" width="500px" height="600px"
            header="Palabra a catalogar: #{wordCatalogatorController.selectedWord.word}"
            widgetVar="activityDialog" modal="true" closable="false">

            <h:panelGrid columns="2" cellpadding="5">

                <p:selectOneMenu id="wordTypes"
                    value="#{wordCatalogatorController.selectedWordType}"
                    style="width: 150px;" converter="#{wordTypeConverter}">
                    <p:ajax
                        listener="#{wordCatalogatorController.wordTypeChangeListener}"
                        update=":myForm:words" />
                    <f:selectItem itemLabel="" itemValue="" />
                    <f:selectItems value="#{wordCatalogatorController.wordTypes}" />
                </p:selectOneMenu>
            </h:panelGrid>

        </p:dialog>
    </h:form>
</h:body>
</html>