# Zurück-Button des Browsers macht Probleme



## PeterRRR (19. Jun 2009)

Hallo!

Ich hab ein JSF-Formular mit 2 Radiobuttons. Dem Benutzer wird eine Frage gestellt und einer der 2 Radios ist die richtige Antwort. In einem Bean sind die Fragen inkl. Antwortmöglichkeiten und korrekter Antwort gespeichert (in einer Liste). Bei Klick auf den Bestätigungs-Button werden im Bean die Antworten sowie der Fragetext geändert (nächstes Element der Liste wird in Variable gespeichert) und die selbe Seite wird mit den veränderten Werten (also neuer Frage und neuen Antworten, ausgelesen aus eben genannter Variable) und einem Hinweis ob die Antwort des Benutzers auf die vorhergehende Frage korrekt war, neu geladen. Wieder ist eine der beiden Antworten korrekt und das Spiel fängt wieder von vorne an. Am Ende wird eine Punktzahl angezeigt.

Das Problem ist jetzt der Zurück-Button des Browsers, klickt man auf diesen, kommt man ja zur letzten Frage zurück und kann die Antwort theoretisch nochmal ändern. Das funktioniert aber auch nicht wirklich, sondern man bekommt einen Validierungsfehler für das Formular. Ich hätte allerdings gerne, dass bei Verwendung des Zurückbuttons und anschließendem Klick auf den Button (also beim Versuch die Antwort nachträglich zu ändern) auf eine entsprechende Seite weitergeleitet wird, die eine Meldung anzeigt, dass das nachträgliche Ändern von Antworten nicht möglich ist.
Ich probiere schon lange herum und krieg es einfach nicht hin.
Hat jemand einen Tipp, wie ich das anstellen könnte? Danke schon jetzt für jede Hilfe!

lg
Peter


----------



## PeterRRR (20. Jun 2009)

Hat wirklich niemand eine Idee, nicht einmal eine kleine? :bahnhof:

Das kann doch eigentlich gar nicht schwer sein, es muss doch irgendwie eine Möglichkeit geben, nur welche?

lg


----------



## Terminator (20. Jun 2009)

Müsstest dich vor der Validierung in den Zyklus einklingen bsw per PhaseListener.
Dann irgendwelche Session Werte checken, ob Frage schon beantwortet wurde und sofort zu RenderResponse jumpen.
Über ein rendered Flag dann die Fragen nicht mehr anzeigen, dafür den Hinweistext.


----------



## PeterRRR (20. Jun 2009)

Danke für die Antwort. Leider sagt mir das jetzt momentan nicht so viel, könntest du das evtl. genauer erklären bzw. gibt es zu diesem Thema vielleicht sogar ein Tutorial?
Danke!

lg
Peter


----------



## Terminator (20. Jun 2009)

Na die Zyklen sollte man aber schon kennen wenn man JSF proggt:

1. Restore View
2. Apply Request Values
3. Process Validations
4. Update Model Values
5. Invoke Application
6. Render Response	



PhaseListner:

public class EPhaseTracker implements PhaseListener, Serializable
{
    public PhaseId getPhaseId()
    {
        return PhaseId.ANY_PHASE;
    }
    public void beforePhase(PhaseEvent e)
    {
        System.out.println("EPhaseTracker." + e.getPhaseId() + "  -  before");
    }
    public void afterPhase(PhaseEvent e)
    {
        System.out.println("EPhaseTracker." + e.getPhaseId() + "  -  after");
    }
} 



faces-config.xml

<lifecycle>
<phase-listener>EPhaseTracker</phase-listener>
</lifecycle>



Mit getPhaseId kannste festlegen wo du dich einklingen willst


----------



## PeterRRR (20. Jun 2009)

Nochmal danke!
Ich hätte jetzt grundsätzlich mal den PhaseListener implementiert, das war ja nicht so das Problem, allerdings ohne konkrete Funktion außer einer einfachen Textausgabe. Mein konkretes Problem jetzt:

Wie kann ich denn checken, ob die Frage schon beantwortet wurde - sprich, wie weiß ich denn, welche Frage dem Benutzer gerade angezeigt wird, wenn er mittels Zurück-Button zurückgegangen ist - der Server bekommt das ja nicht wirklich mit, oder? Wie bereits gesagt, in meinem Bean ist eine Liste mit Fragen wovon immer genau eine in eine eigene Variable gespeichert wird, diese Variable wird dann dem Benutzer mittels JSF angezeigt. Geht der Benutzer jetzt zurück und beantwortet eine Frage nochmal, "glaubt" der Server, der Benutzer beantwortet die Frage, die in der Variable gespeichert ist, das ist ja das eigentliche Problem.

lg
Peter


----------



## PeterRRR (20. Jun 2009)

Ich hab jetzt mal ein sehr einfaches Beispiel erstellt, das mein Problem deutlich machen sollte:

*Frage.java*


```
package test;

public class Frage {

	private String frage;
	private String antwort1;
	private String antwort2;
	private String korrekt;
	
	public Frage(String f, String a1, String a2, String k)
	{
		setFrage(f);
		setAntwort1(a1);
		setAntwort2(a2);
		setKorrekt(k);
	}
	
	public String getFrage() {
		return frage;
	}
	public void setFrage(String frage) {
		this.frage = frage;
	}
	public String getAntwort1() {
		return antwort1;
	}
	public void setAntwort1(String antwort1) {
		this.antwort1 = antwort1;
	}
	public String getAntwort2() {
		return antwort2;
	}
	public void setAntwort2(String antwort2) {
		this.antwort2 = antwort2;
	}
	public String getKorrekt() {
		return korrekt;
	}
	public void setKorrekt(String korrekt) {
		this.korrekt = korrekt;
	}
}
```

*MeineFrage.java (Bean)*


```
package test;

import java.io.Serializable;
import java.util.ArrayList;
import javax.faces.event.ActionEvent;

public class MeineFrage implements Serializable{

	private static final long serialVersionUID = 1L;
	private ArrayList<Frage> frageliste = new ArrayList<Frage>();
	private Frage aktuelleFrage;
	private int counter = 0;
	private boolean ende = false;
	private String userantwort;
	private int richtigeAntworten = 0;
	
	public MeineFrage()
	{
		frageliste.add(new Frage("Frage 1", "Antwort 1.1", "Antwort 1.2", "Antwort 1.1"));
		frageliste.add(new Frage("Frage 2", "Antwort 2.1", "Antwort 2.2", "Antwort 2.2"));
		frageliste.add(new Frage("Frage 3", "Antwort 3.1", "Antwort 3.2", "Antwort 3.1"));
		aktuelleFrage = frageliste.get(counter);
	}
	
	public void checkAntwort(ActionEvent e)
	{
		if(getUserantwort().equals(aktuelleFrage.getKorrekt()))
			richtigeAntworten++;
		
		counter++;
		
		if(counter==frageliste.size())
			ende=true;
		else
			aktuelleFrage = frageliste.get(counter);
	}

	public String getUserantwort() {
		return userantwort;
	}

	public void setUserantwort(String userantwort) {
		this.userantwort = userantwort;
	}
	
	public ArrayList<Frage> getFrageliste() {
		return frageliste;
	}

	public void setFrageliste(ArrayList<Frage> frageliste) {
		this.frageliste = frageliste;
	}

	public int getRichtigeAntworten() {
		return richtigeAntworten;
	}

	public void setRichtigeAntworten(int richtigeAntworten) {
		this.richtigeAntworten = richtigeAntworten;
	}

	public boolean isEnde() {
		return ende;
	}

	public void setEnde(boolean ende) {
		this.ende = ende;
	}

	public Frage getAktuelleFrage() {
		return aktuelleFrage;
	}

	public void setAktuelleFrage(Frage aktuelleFrage) {
		this.aktuelleFrage = aktuelleFrage;
	}
}
```

*faces-config.xml*


```
<managed-bean>
		<managed-bean-name>frage</managed-bean-name>
		<managed-bean-class>test.MeineFrage</managed-bean-class>
		<managed-bean-scope>session</managed-bean-scope>
	</managed-bean>
```

*test.jsp (Auszug)*


```
<f:view>
	<html>
		<head>
			<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
			<title>Test</title>
		</head>
		<body>
			<h:form id="antwortForm" rendered="#{!frage.ende}">
				<h:outputText value="#{frage.aktuelleFrage.frage}" />
				<h:selectOneRadio layout="pageDirection" id="antworten" value="#{frage.userantwort}">
					<f:selectItem id="antwort1" itemLabel="#{frage.aktuelleFrage.antwort1}" itemValue="#{frage.aktuelleFrage.antwort1}" />
					<f:selectItem id="antwort2" itemLabel="#{frage.aktuelleFrage.antwort2}" itemValue="#{frage.aktuelleFrage.antwort2}" />
			   	</h:selectOneRadio>
			   	<h:commandButton value="Klick" actionListener="#{frage.checkAntwort}" />
			</h:form>
			<h:outputText value="#{frage.richtigeAntworten}" rendered="#{frage.ende}" />
		</body>
	</html>
</f:view>
```


----------



## JanHH (21. Jun 2009)

Kannst Du nicht einfach die aktuelle Frage als hidden Value mit in die Seite einbauen, und dann in checkAntwort überprüfen, ob die Frage, die in dem hidden Value angegeben ist, auch die ist, die erwartet wird? Und wenn dies nicht der Fall ist, kann man davon ausgehen dass der User rumnavigiert hat, entsprechend einen Hinweistext anzeigen und einfach nochmal die aktuelle Frage wiederholen.


----------



## PeterRRR (21. Jun 2009)

Das hatte ich mir auch schon einmal gedacht, bevor ich hier gepostet hab, nur wie soll ich das anstellen?

Wenn ich als Wert für das Hidden-Input den Text der aktuellen Frage nehme, also so:


```
<h:form id="antwortForm" rendered="#{!frage.ende}">
	<h:outputText value="#{frage.aktuelleFrage.frage}" />
	<h:selectOneRadio layout="pageDirection" id="antworten" value="#{frage.userantwort}">
		<f:selectItem id="antwort1" itemLabel="#{frage.aktuelleFrage.antwort1}" itemValue="#{frage.aktuelleFrage.antwort1}" />
		<f:selectItem id="antwort2" itemLabel="#{frage.aktuelleFrage.antwort2}" itemValue="#{frage.aktuelleFrage.antwort2}" />
	</h:selectOneRadio>
	<h:inputHidden value="#{frage.aktuelleFrage.frage}" />
	<h:commandButton value="Klick" actionListener="#{frage.checkAntwort}" />
</h:form>
```

bringt mir das garnichts, weil der Wert dann ja mit getter/ setter des Textes der aktuellen Frage verknüpft ist fünf Zeilen weiter oben im Code im Output-Text der Fall, das Hidden-Input wäre also gänzlich sinnlos.

Verknüpfe ich das Hidden-Input aber mit einer eigenen String-Variable, beispielsweise so:


```
<h:inputHidden value="#{frage.hiddenFrage}" />
```

ändert sich der Wert ja nie, da immer der gleiche Wert aus der Variable ausgelesen und ins Hidden geschrieben wird.

Oder hab ich da was falsch verstanden?

lg


----------



## JanHH (25. Jul 2009)

Mh also du hast applikationsintern (irgendeine session scope bean) eine currentQuestin.

der getter für den hidden-parameter liest und kopiert sie


```
getExcpectedQuestion()
{
this.expectedQuestion=currentQuestion;
return excpetedQuestion;
}

setExceptedQuestion(String s)
{
excpetedQuestion=s;
}
```

und dann musst Du in der action-Methode nur vergleichen, ob currentQuestion und exceptedQuestion identisch sind.


----------

