JSF Primefaces: DataTable Ajax Update - Weiterleitung von anderer Seite

  • Themenstarter Themenstarter transdenzentral
  • Beginndatum Beginndatum
T

transdenzentral

Gast
Hallo Leute,

ich habe folgendes KSKB, was die Problematik darstellt. Vielleicht kurze Erklärung, bevor ich das eigentliche Problem schildere.

Setup:

  • Tomcat 7.0
  • Primefaces 3.4.1
  • Eclipse Juno
  • Test Browser: Firefox 16.0.2

Es gibt im Prinzip zwei Beans:

  • einmal ein einfacher Login (der eigentlich der Einfachheit halber nichts tut, außer die nächste Seite zurückgeben).
  • einmal eine Bean für die Tabelle, die ein paar Dummy Daten initalisiert, ein einfaches Datenmodell enthält und eben einen ausgewählten Datensatz speichern soll.

Dazu noch 2 XHTML Seiten

  • index.hxtml: Enthält einfach einen Button, der auf die LoginBean zugreift und auf die table.xhtml weiterleitet.
  • table.xhtml: Zeigt eine Tabelle an und soll über das Selektieren eines Datensatzes, diesen in das entsprechende Datenfeld der SomeSampleDataTableBean schreiben. Wenn man auf den darunterliegenden Button klickt, soll auf diesem Wert gearbeitet werden. (Den Fall, dass nichts ausgewählt ist und man trotzdem drauf drückt, sei mal zu vernachlässigen)

Die Problematik ist folgende (lässt sich in zwei Fälle aufteilen):

  1. Gehe ich direkt über den Browser auf die table.xhtml Seite, so geht das Selektieren einer Tabellenzeile sofort - in diesem Fall klappt alles, wie ich es erwarte.
  2. Gehe ich indirekt, also zuerst über die index.xhtml Seite (per Button Interaktion), auf die table.xhtml Seite, so wird das erste Selektieren einer Tabellenzeile praktisch "verschluckt" und die Selektion praktisch vom System nicht angenommen. Beim zweiten Selektieren klappt dann alles, wie ich es erwarte.

Prinzipiell geht es mir also um den 2.) Fall. Was mach ich falsch? Habe ich einen Denkfehler? Gibt's eine Lösung, sodass das funktioniert, wie ich mir das vorstelle?

Vielen Dank,
transdenzentral


Hier das KSKB:
Java:
package de.test.beans;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@SuppressWarnings("serial")
@ManagedBean
@SessionScoped
public class SimpleLoginBean implements Serializable {

	public SimpleLoginBean() {

	}

	public String login() {
		return "table.xhtml";
	}
}

Java:
package de.test.beans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import de.test.data.SomeSampleData;
import de.test.data.SampleTableDataModel;

@ManagedBean
@SessionScoped
@SuppressWarnings("serial")
public class SomeSampleDataTableBean implements Serializable {

	private final SampleTableDataModel dataModel;

	private SomeSampleData selectedData;

	public SomeSampleDataTableBean() {
		// fill with dummy data...
		List<SomeSampleData> dummy = new ArrayList<SomeSampleData>();
		String[] names = new String[] { "Test 1", "Test 2", "Test 3", };
		long a = 0;
		for (String name : names) {
			SomeSampleData q = new SomeSampleData(a);
			q.setName(name);
			dummy.add(q);
			a++;
		}
		// end of dummy data...
		dataModel = new SampleTableDataModel(dummy);

	}

	public void showSelected() {
		System.out.println("Selected: " + selectedData.getName());
	}

	public SampleTableDataModel getDataModel() {
		return dataModel;
	}

	public SomeSampleData getSelectedData() {
		return selectedData;
	}

	public void setSelectedData(SomeSampleData selectedData) {
		this.selectedData = selectedData;
	}
}


Java:
package de.test.data;

import java.util.List;

import javax.faces.model.ListDataModel;

import org.primefaces.model.SelectableDataModel;

public class SampleTableDataModel extends ListDataModel<SomeSampleData> implements
		SelectableDataModel<SomeSampleData> {

	public SampleTableDataModel(List<SomeSampleData> data) {
		super(data);
	}

	@Override
	@SuppressWarnings("unchecked")
	public SomeSampleData getRowData(String rowKey) {

		List<SomeSampleData> data = (List<SomeSampleData>) getWrappedData();
		for (SomeSampleData object : data) {
			if (object.getId().equals(Long.parseLong(rowKey))) {
				return object;
			}
		}
		return null;
	}

	@Override
	public Object getRowKey(SomeSampleData data) {
		return data.getId();
	}

}

Java:
package de.test.data;
import java.io.Serializable;

@SuppressWarnings("serial")
public class SomeSampleData implements Serializable{

	private String name;
	private Long id;

	public SomeSampleData(long id) {
		super();
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Questionnaire [name=" + name + "]";
	}

	public Long getId() {
		return id;
	}

}

HTML:
<!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></h:head>
<h:body>
<h:form id="login">
<p:commandButton id="loginButton" value="Login" action="#{simpleLoginBean.login()}"></p:commandButton>
</h:form>

</h:body>
</html>

HTML:
<!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></h:head>
<h:body>
	<h:form id="test">

		<p:dataTable id="sample" var="data"
			value="#{someSampleDataTableBean.dataModel}"
			selection="#{someSampleDataTableBean.selectedData}"
			selectionMode="single">
			<f:facet name="testdata"></f:facet>
			<p:ajax event="rowSelect" update="@form" />
			<p:column>#{data.name}</p:column>
		</p:dataTable>
	</h:form>

	<h:form id="testButton">
		<p:commandButton id="command"
			action="#{someSampleDataTableBean.showSelected()}" value="Test"></p:commandButton>
	</h:form>

</h:body>
</html>
 
Zuletzt bearbeitet von einem Moderator:
Guten Morgen,

anbei 2 Fragen)
- hat es einen Grund, wieso du ein Datamodel verwendest ?
- warum soll die Datatable neu gerendert werden, wenn eine "row" selektiert wird,
sehe keine implementierte Funktion, die bei Auswahl einer Row irgend etwas modifiziert an der Datatable, dass diese
neu gerendert werden müsste.

bei Primefaces 3.4.1 kannst du auf das Modell zurückgreifen:
PrimeFaces - ShowCase

wenn du es aber dennoch wissen willst, schau dir mal die Ajax Response an, welche beim ersten mal (wo es nicht funktioniert)
zurück gegeben wird.


------------------------------------
Wenn du eine Aktion ausführen möchtest, implementiere dir die folgenden Listener:
<p:ajax event="rowSelect" listener="#{tableBean.onRowSelect}"
update=":form:display :form:growl" oncomplete="carDialog.show()" />
<p:ajax event="rowUnselect" listener="#{tableBean.onRowUnselect}" update=":form:growl"/>

(hier wird nicht die Datatable geupdated, sondern der Dialog und der growl -> FacesMessage)


Grüße
 
Zuletzt bearbeitet:
Hi du,

hat es einen Grund, wieso du ein Datamodel verwendest ?

Ja, es hat einen Grund, warum ich ein DataModel verwende. Dieser ist aber mehr auf die eigentliche Anwendung zugeschnitten. Deshalb kommt das für das KSKB etwas verloren rüber 😉

warum soll die Datatable neu gerendert werden, wenn eine "row" selektiert wird,
sehe keine implementierte Funktion, die bei Auswahl einer Row irgend etwas modifiziert an der Datatable, dass diese
neu gerendert werden müsste.

Darin liegt vielleicht des eigentliche Problem. Ich möchte die ausgewählte Reihe (hinter der ja ein Objekt steht) in ein Datenfeld der Bean schreiben über
HTML:
selection="#{someSampleDataTableBean.selectedData}

Das Ganze floppt allerdings (auch wenn man das Beispiel von PF 3.4.1. im eigenen Projekt ausprobiert), denn es wird kein Wert an diese Stelle geschrieben und man freut sich über "null" 😉 - Hintergrund ist also, dass die Selektion von Daten nicht wie gewünscht funktioniert (vielleicht habe ich auch einen kompletten Denkfehler).

Fakt ist, dass das von Dir verlinkte Beispiel in konkreter Form bei mir überhaupt nicht funktioniert, da in dem Datenfeld für die Selektion dann immer "null" steht.

Ich hatte das vorher auch über die besagten Listener gelöst (vgl. InstantRowSelect Beispiel im ShowCase), aber ich finde es doch irgendwie "hässlich", wenn ich da rumcasten muss, um das ausgewählte Objekt irgendwo zwischen zu speichern.

Die Dokumentation sagt dazu ja das im Anhang zu findende... - versteh also eigentlich nicht, warum das Ganze nicht funktioniert 😀
 

Anhänge

  • pfDoku.PNG
    pfDoku.PNG
    35,2 KB · Aufrufe: 45
Zuletzt bearbeitet von einem Moderator:
adde testweise nen System.out.println() in die Setter methode des Selectierten Objekten, wenn es nicht leer ist.

tauchen irgendwelche Fehler in der catalina.out auf, wenn sich die Row nicht selektieren lässt beim ersten mal ?
welches implementierung und Version von JSF 2 verwendest du ?
 
  • JSF 2.1
  • Apache MyFaces 2.1.5

Ich habe mal in der dahinterliegenden Bean die besagten Syso Statements eingebaut.

Java:
public SomeSampleData getSelectedData() {
		System.out.println("getSelectedData()");
		return selectedData;
	}

	public void setSelectedData(SomeSampleData selectedData) {
		System.out.println("setSelectedData()");
		this.selectedData = selectedData;
	}

Unter Verwendung diese table.xhtml wird der Setter des selektierten Objekts nicht aufgerufen:

HTML:
<!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></h:head>
<h:body>
	<h:form id="test">

		<p:dataTable id="sample" var="data"
			value="#{someSampleDataTableBean.dataModel}" selectionMode="single"
			selection="#{someSampleDataTableBean.selectedData}">
			<f:facet name="testdata"></f:facet>

			<p:column>#{data.name}</p:column>
		</p:dataTable>
	</h:form>

	<h:form id="testButton">
		<p:commandButton id="command"
			action="#{someSampleDataTableBean.showSelected()}" value="Test"></p:commandButton>
	</h:form>

</h:body>
</html>

Verwende ich dann
Code:
<p:ajax event="rowSelect"
				update="#{someSampleDataTableBean.selectedData}" />
bzw.
Code:
<p:ajax event="rowSelect"
				update="@form" />

wird der Setter immer aufgerufen. Allerdings auch nur, wenn ich beim ersten Mal direkt auf die Seite komme (URL: localhost:8080/Primefaces-KSKB/table.xhtml).

Komme ich über die index.xhtml auf die table.xhtml stellt sich das besagte Problem ein, dass die erste Selektion nicht zieht.


Fehlermeldungen gibt es in dieser Situation keinen.
 
Ist glaube ich nen Bug .. du musst in der DataTable eine rowKey mit angeben.
Der sollte wenn möglich unique sein!
[XML]

<p:dataTable id="sample" var="data"
value="#{someSampleDataTableBean.dataModel}" selectionMode="single"
selection="#{someSampleDataTableBean.selectedData}" rowKey="#{data.id}">
<f:facet name="testdata"></f:facet>

<p:column>#{data.name}</p:column>
</p:dataTable>

[/XML]
 
@jwiesmann

Das funktioniert leider gar nicht. Der rowKey sollte auf Grund des DataModel eigentlich nicht gebraucht werden (Primefaces Dokumentation).

Problem bleibt also weiterhin bestehen ...
 
Zuletzt bearbeitet von einem Moderator:
muss der Testbutton sein eigenes Form haben? Versuch mal den Button in das Tabellenform mit reinzunehmen, oder gib dem Testbutton mal ein process=":test" Attribut. Was macht eigentlich die "testdata" facet?.
 
Zuletzt bearbeitet:
muss der Testbutton sein eigenes Form haben? Versuch mal den Button in das Tabellenform mit reinzunehmen, oder gib dem Testbutton mal ein process=":test" Attribut. Was macht eigentlich die "testdata" facet?.

Die Facet ist der Tabellenkopf (vgl. Showcase PF. Ich hatte nur vergessen etwas reinzuschreiben bzw. den Namen auch wirklich auf "header" zu setzen für das KSKB.


Code:
<!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></h:head>
<h:body>
	<h:form id="test">

		<p:dataTable id="sample" var="data"
			value="#{someSampleDataTableBean.dataModel}"
			selection="#{someSampleDataTableBean.selectedData}"
			selectionMode="single">

			<f:facet name="header">Testdata</f:facet>

			<p:column>#{data.name}</p:column>

			<f:facet name="footer">
				<p:commandButton id="command2"
					action="#{someSampleDataTableBean.showSelected()}" value="Test"></p:commandButton>
			</f:facet>
		</p:dataTable>
	</h:form>


</h:body>
</html>

Aber selbst, wenn ich den Button reinziehe in die Tabelle, wird der erste Klick (wenn man vom Index kommt) verschluckt.

Ob in selbiger Form oder außerhalb spielt also imho keine Rolle?! (im eigentlichen Projekt liegt der Button allerdings auch in einer anderen Form...)
 
Ist zwar etwas von hinten durch die Brust, aber funktioniert vielleicht sowas:

Java:
String uri = "index.xhtml";
FacesContext.getCurrentInstance().getExternalContext().redirect(uri);

Weiß zwar noch nicht obs weiterhelfen kann, aber einen Versuch kann man ja machen 😀
 
hab deinen Code mal fast original ausprobiert, bei mir geht alles, auch nach redirect 🙂
Ich benutze allerdings Mojarra 2.1.10 und PF 3.4.2. Erfahrungen mit Myfaces hab ich nicht. Es kann durchaus sein, dass es was mit der jsf-impl zu tun hat. Bin bisher immer mit der Version, die PF auch im Showcase fährt ganz gut klarkgekommen.
Wenn etwas erst beim zweiten Request funktioniert, ist meistens immer was mit dem AJAX request komisch oder er findet irgendwelche ids nicht. Versuch mal bitte den Loginbutton mit ajax="false" aufzurufen.
 
hab deinen Code mal fast original ausprobiert, bei mir geht alles, auch nach redirect 🙂
Ich benutze allerdings Mojarra 2.1.10 und PF 3.4.2. Erfahrungen mit Myfaces hab ich nicht. Es kann durchaus sein, dass es was mit der jsf-impl zu tun hat. Bin bisher immer mit der Version, die PF auch im Showcase fährt ganz gut klarkgekommen.
Wenn etwas erst beim zweiten Request funktioniert, ist meistens immer was mit dem AJAX request komisch oder er findet irgendwelche ids nicht. Versuch mal bitte den Loginbutton mit ajax="false" aufzurufen.

Jo, wenn ich ajax="false" beim Loginbutton setze, dann klappts auch in meiner Konfiguration! Danke!
 

Zurück
Oben