JSF ArrayList über InputText befüllen

P

Phoe

Gast
Hallo zusammen,


ich zerbreche mir seit 2 Tagen den Kopf (vermutlich) über eine absolute Banalität.

Ich habe eine ArrayList "apartment" in der Klasse "ApartmentList" mit 4 Werten gefüllt und möchte
nun per Formular weitere Werte hinzufügen. Die Liste wird zwar weiter gefüllt (zumindest laut #{apartmentList.apartment.size()} ), allerdings offenbar mit Nullwerten. Gebe ich die Liste per <h:dataTable> aus, werden nur die 4 vorab eingefügten Werte angezeigt, nicht jedoch die aus dem Formular stammenden.

Zur Verdeutlichung hier der Code:

apartment.java:
Java:
package kleinanzeigen;
import java.util.Date;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;

@ManagedBean(name="apartments")
@ApplicationScoped
public class Apartments {
	
	private String apartment_name;
	private Integer square_meter;
	private String location;
	private Double price;
	private Boolean garden;
	private Boolean balcony;
	private String text;
	private Date addDate;


	public Apartments() {
		
	}
	
	public Apartments(String apartment_name, Integer square_meter, String location, Double price, Boolean garden, Boolean balcony, String text) {
		this.apartment_name=apartment_name;
		this.square_meter=square_meter;
		this.location=location;
		this.price=price;
		this.garden=garden;
		this.balcony=balcony;
		this.text=text;
	}
	
	public String getApartment_name() {
		return apartment_name;
	}

	public void setApartment_name(String appartment_name) {
		this.apartment_name = appartment_name;
	}
	
...

ApartmentList.java:
Java:
package kleinanzeigen;

import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;

@ManagedBean(name="apartmentList")
@ApplicationScoped
public class ApartmentList {
	
	private List<Apartments> apartment = new ArrayList<Apartments>();
	
	public ApartmentList() {
		this.apartment.add(new Apartments("3-Zimmer-Wohnung",95,"Stuttgart",(double) 950.00,false,true,"Keine Tiere"));
		this.apartment.add(new Apartments("4-Zimmer-Wohnung",120,"Ludwigsburg",(double) 1150.00,true,false,"Keine Kinder"));
		this.apartment.add(new Apartments("Penthouse-Wohnung",180,"Kornwestheim",(double) 1700.00,false,true,"Ohne Provision"));
		this.apartment.add(new Apartments("Großer Loft",150,"Heilbronn",(double) 2500.00,false,true,"Küche kann übernommen werden"));
	}
	
	public List<Apartments> getApartment() {
		return apartment;
	}
	
	public void setApartment(List<Apartments> apartment) {
		this.apartment=apartment;
	}
	
	public String addEntry() {
		apartment.add(new Apartments());
		return "apartments.xhtml";
	}
}

addApartment.xhtml (Formular + commandButton mit Methodenaufruf):
[XML]<h:form headerClass="apartment">
<h:panelGrid columns="2" border="1">
<h:eek:utputLabel for="#{msgs.apartment_name}" value="#{msgs.apartment_name}:" />
<h:inputText value="#{apartments.apartment_name}" id="apartment_name" required="true" immediate="true" />

<h:eek:utputLabel for="#{msgs.location}" value="#{msgs.location}:" />
<h:inputText value="#{apartments.location}" id="location" required="true" immediate="true" />

<h:eek:utputLabel for="#{msgs.square_meter}" value="#{msgs.square_meter}:" />
<h:inputText value="#{apartments.square_meter}" id="square_meter" required="true" immediate="true" />

<h:eek:utputLabel for="#{msgs.price}" value="#{msgs.price}:" />
<h:inputText value="#{apartments.price}" id="price" required="true" immediate="true" />

<h:eek:utputLabel for="#{msgs.garden}" value="#{msgs.garden}:" />
<h:selectBooleanCheckbox value="#{apartments.garden}" immediate="true" id="garden" required="true" />

<h:eek:utputLabel for="#{msgs.balcony}" value="#{msgs.balcony}:" />
<h:selectBooleanCheckbox value="#{apartments.balcony}" immediate="true" id="balcony" required="true" />

<h:eek:utputLabel for="#{msgs.text}" value="#{msgs.text}:" />
<h:inputTextarea value="#{apartments.text}" id="text" immediate="true" />

<h:inputHidden value="#{apartments.addDate}">
<f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss"/>
</h:inputHidden>

</h:panelGrid>

<h:commandButton value="#{msgs.confirm}" action="#{apartmentList.addEntry}" />
<h:commandButton value="#{msgs.cancel}" action="cancelled.xhtml" immediate="true" />

</h:form>[/XML]

apartments.xhtml (Ausgabe der Liste "apartment"):
[XML]
<h:dataTable var="apartment" value="#{apartmentList.apartment}" border="1">
<h:column>
<f:facet name="header">
<h:eek:utputText value="#{msgs.apartment_name}" />
</f:facet>
<h:eek:utputText value="#{apartment.apartment_name}" />
</h:column>

<h:column>
<f:facet name="header">
<h:eek:utputText value="#{msgs.location}" />
</f:facet>
<h:eek:utputText value="#{apartment.location}" />
</h:column>

<h:column>
<f:facet name="header">
<h:eek:utputText value="#{msgs.square_meter}" />
</f:facet>
<h:eek:utputText value="#{apartment.square_meter}" />
</h:column>

<h:column>
<f:facet name="header">
<h:eek:utputText value="#{msgs.price}" />
</f:facet>
<h:eek:utputText value="#{apartment.price}" />
</h:column>

<h:column>
<f:facet name="header">
<h:eek:utputText value="#{msgs.garden}" />
</f:facet>
<h:eek:utputText value="#{apartment.garden}" />
</h:column>

<h:column>
<f:facet name="header">
<h:eek:utputText value="#{msgs.balcony}" />
</f:facet>
<h:eek:utputText value="#{apartment.balcony}" />
</h:column>

<h:column>
<f:facet name="header">
<h:eek:utputText value="#{msgs.text}" />
</f:facet>
<h:eek:utputText value="#{apartment.text}" />
</h:column>

</h:dataTable>[/XML]

Ich vermute mal, dass mir der Standard-Konstruktor in der "Apartment.java" einen Strich durch die Rechnung macht, aber ohne den kann ich das Formular in der "addAparatment.xhtml" nicht befüllen.

Schieße ich womöglich komplett am Ziel vorbei? Bin für jede Hilfe dankbar. 8)
 

Templarthelast

Bekanntes Mitglied
Werden dir den die zusätzlichen Einträge im Logger ausgegeben? Falls ja vermute ich mal, dass du die datatable nicht updatest und die neusten werte einfach nicht abgerufen werden.
 
P

Phoe

Gast
Danke für den Hinweis! Aber wenn ich die vordefinierten Listeneinträge in der Bean anpasse (z.B. ein "add" entferne), aktualisiert sich auch die dataTable - Ausgabe.

Die Console gibt mir eine "NoClassDefFoundError" - Fehlermeldung:

Code:
Warnung: Identifier for execute FlashMap was lost on the postback, thus FlashScope information is gone.
Aug 18, 2012 8:35:47 PM org.apache.myfaces.renderkit.html.HtmlLabelRenderer encodeBegin
Warnung: Attribute 'for' of label component with id form:j_id2049579611_7a2a1e5a is not defined
Aug 18, 2012 8:35:47 PM org.apache.myfaces.renderkit.html.HtmlLabelRenderer encodeBegin
Warnung: Attribute 'for' of label component with id form:j_id2049579611_7a2a1e48 is not defined
Aug 18, 2012 8:35:47 PM org.apache.myfaces.renderkit.html.HtmlLabelRenderer encodeBegin
Warnung: Attribute 'for' of label component with id form:j_id2049579611_7a2a1e6e is not defined
Aug 18, 2012 8:35:47 PM org.apache.myfaces.renderkit.ErrorPageWriter handleThrowable
Schwerwiegend: An exception occurred
javax.faces.FacesException: java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config
	at org.apache.myfaces.shared_impl.context.ExceptionHandlerImpl.wrap(ExceptionHandlerImpl.java:241)
	at org.apache.myfaces.shared_impl.context.ExceptionHandlerImpl.handle(ExceptionHandlerImpl.java:156)
	at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:258)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:191)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config
	at org.apache.myfaces.view.jsp.JspViewDeclarationLanguage.buildView(JspViewDeclarationLanguage.java:86)
	at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:66)
	at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:239)
	... 17 more

Ist die Vorgehensweise denn allgemein richtig oder muss ich eventuell doch mit ActionListenern/ActionEvents arbeiten (bislang war auch dies leider nicht von Erfolg gekrönt)?
 
P

Phoe

Gast
Wenn ich der Bean "ApartmentList" die Property "apartment" hinzufüge, gibt's eine NullPointerException.

Code:
javax.el.ELException: /addApartment.xhtml at line 74 and column 81 action="#{apartmentList.addEntry}": java.lang.NullPointerException

Caused by:
java.lang.NullPointerException - /addApartment.xhtml at line 74 and column 81 action="#{apartmentList.addEntry}": java.lang.NullPointerException

Kann es sein, dass die Formularwerte gar nicht an die Methode übergeben werden? JSF erlaubt doch aber, soweit ich weiß, keine direkte Übergabe von Werte beim Methodenaufruf, oder? Zumindest nicht ohne Weiteres. Das hier sollte demnach nicht funktionieren:

addApartment.xhtml:
[XML] <h:commandButton value="#{msgs.confirm}" action="#{otherList.addEntry(Wert1,Wert2,Wert3,Wert4,Wert5,Wert6,Wert7)}" />[/XML]
 

Fant

Bekanntes Mitglied
Java:
public String addEntry() {
        apartment.add(new Apartments());
        return "apartments.xhtml";
    }

Wenn du weiterhin so Einträge zu deiner Liste hinzufügst, dann ist doch klar, dass da nix gescheites ankommt. Du fügst nicht das Object hinzu, in das du zuvor die Formulardaten schreibst, sondern ein komplett neues, in dem natürlich dann noch nix drin steht.
 
P

Phoe

Gast
Java:
public String addEntry() {
        apartment.add(new Apartments());
        return "apartments.xhtml";
    }

Wenn du weiterhin so Einträge zu deiner Liste hinzufügst, dann ist doch klar, dass da nix gescheites ankommt. Du fügst nicht das Object hinzu, in das du zuvor die Formulardaten schreibst, sondern ein komplett neues, in dem natürlich dann noch nix drin steht.

Okay. Wie bekomme ich denn die Formulardaten in das neue Objekt? Ohne JSF würde ich beim Methodenaufruf ja einfach Werte übergeben, aber JSF lässt das nicht zu.

Java:
public String addEntry() {
        apartment.add(new Apartments(Wert1, Wert2 etc.));
        return "apartments.xhtml";
    }
 
P

Phoe

Gast
Ein Kommilitone hat mir soeben die Augen geöffnet. Es ist tatsächlich äußerst trivial. Hätte mir schon Dank Fants Hinweis auffallen müssen.

Zuerst wird der Methodenaufruf im "commandButton" um die Bean (apartments) erweitert, in der die Werte per Formular erfasst wurden.

addApartment.xhtml:
[XML] <h:eek:utputLabel for="#{msgs.text}" value="#{msgs.text}:" />
<h:inputTextarea value="#{apartments.text}" id="text" immediate="true" />

<h:inputHidden value="#{apartments.addDate}">
<f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss"/>
</h:inputHidden>

</h:panelGrid>

<h:commandButton value="#{msgs.confirm}" action="#{apartmentList.addEntry(apartments)}" />[/XML]

Dann wird die Methode in der Klasse "ApartmentList" angepasst und schon funktioniert es.

ApartmentList.java:
Java:
	public String addEntry(Apartments newApartment) {
		apartment.add(new Apartments(newApartment.getApartment_name(),newApartment.getSquare_meter(),newApartment.getLocation(),newApartment.getPrice(),newApartment.getBalcony(),newApartment.getGarden(),newApartment.getText()));
		return "apartments.xhtml";
	}

Thx!
 

Fant

Bekanntes Mitglied
Nenene ... das ist immer noch großer Blödsinn. Funktioniert das denn überhaupt? Da ist aber leider insgesamt so viel krumm und schief, dass man gar nicht so genau weiß, wo man anfangen soll zu korrigieren.

Ich versuch mal die wesentlichen Punkte zusammenzutragen, die mir aufgefallen sind:
- Zunächst mal sollte deine Bean "Apartments" vermutlich gar keine sein. Die Klasse dient doch nur dazu die Daten, die ein Apartment beschreiben, zu kapseln. Dann solltest du die Klasse auch genau hierfür benutzen. Streich hier einfach die beiden Klassen-Annotationen und mach die Klasse dadurch zu einer "ganz normalen Klasse".
Variablennamen schreibt man in Java übrigens üblicherweise in lowerCamelCase. Also squareMeter statt square_meter usw.
Außerdem ist das s bei "Apartments" irgendwie ... fehl am Platz. Eine Instanz dieser Klasse entspricht doch exakt einem Apartment. Dann sollte mMn die Klasse auch wirklich nur Apartment heißen.

- Im Gegenzug braucht deine eigentliche Kontroller-Klasse (also die Bean, mit der du mit der View interagierst - in deinem Fall also ApartmentList) dann ein Attribut vom Typ Apartment. In dieses Attribut schreibst du dann die Benutzereingaben und dann kannst du damit innerhalb der KontrollerKlasse machen was du willst - also zB deiner Liste hinzufügen.
Fügst du deiner Klasse Apartment übrigens noch einen Copy-Konstruktor hinzu, so kannst du dir hinterher ein wenig Tipparbeit sparen.

- Was mich zusätzlich noch anspringt ist, dass deine JSF-Seiten nicht fehlerfrei sind. Schau dir mal die ganzen Warnungen in Beitrag #3 an. Das "for"-Attribut beim outputLabel-Tag bezieht sich immer auf eine bestimmte ID. Und zwar auf die ID derjenigen Komponente, die du damit beschriften willst. Statt
HTML:
<h:outputLabel for="#{msgs.text}" value="#{msgs.text}:" />
<h:inputTextarea value="#{apartments.text}" id="text" immediate="true" />
sollte es also
HTML:
<h:outputLabel for="text" value="#{msgs.text}:" />
<h:inputTextarea value="#{apartments.text}" id="text" immediate="true" />
heißen.
Außerdem bezweifle ich, dass
HTML:
        <h:inputHidden value="#{apartments.addDate}">
            <f:convertDateTime pattern="dd.MM.yyyy HH:mm:ss"/>
        </h:inputHidden>
wirklich das macht, was es soll. Ich würde an deiner Stelle einfach innerhalb der KontrollerKlasse ein neues Datum und in die Apartment-Instanz schreiben, sobald das gewünscht ist. Dann hat der Benutzer auch keine Möglichkeit an dieser Stelle Unsinn in das Datumsfeld einzutragen.
 
P

Phoe

Gast
Wow. o_O Also funktionieren tut es tatsächlich (warum auch immer).

Ich nutze die Bean "Apartments", um diese im Formular aufrufen zu können:

Java:
		<h:outputLabel for="location" value="#{msgs.location}:" />
		<h:inputText  value="#{apartments.location}" id="location" required="true" immediate="true"  />

Wenn ich hierfür die Kontroller-Klasse verwenden würde, bräuchte ich vermutlich jenes "Attribut", von dem du schreibst. Wie füge ich das hinzu? Wäre es denn grundlegend falsch, wenn ich die Formulardaten weiterhin an die Bean "Apartments" übergebe und die "ApartmentList" lediglich für die Ausgabe der Daten nutze?

Das mit den Variablennamen korrigiere ich gleich mal (hatte mir nur gemerkt, dass Klassennamen groß geschrieben werden). Auch die Namensgebung der Klassen (Apartmens) ist, zugegeben, etwas unglücklich. Aber erst die Pflicht, dann die Kür. ;)

Die "for" - Fehler korrigiere ich auf jeden Fall. Hatte in meinem jugendlichen Leichtsinn angenommen, die ID des outputLabel - Tags aus den message.properties ziehen zu können. Schlussendlich liefert der Aufruf "#{msgs.text}" ja nichts anderes zurück als "text".

Besten Dank schonmal!
 

Fant

Bekanntes Mitglied
Ich nutze die Bean "Apartments", um diese im Formular aufrufen zu können:

Java:
		<h:outputLabel for="location" value="#{msgs.location}:" />
		<h:inputText  value="#{apartments.location}" id="location" required="true" immediate="true"  />

Wenn ich hierfür die Kontroller-Klasse verwenden würde, bräuchte ich vermutlich jenes "Attribut", von dem du schreibst. Wie füge ich das hinzu?

Ganz "normal"..

Java:
public class ApartmentList {

   (...)
   private Apartment apartment;
   public getApartment() { ... }
   public setApartment(Apartment app) { ... }    

}

In deinem Formular greifst du dann wie folgt darauf zu:
HTML:
		<h:outputLabel for="location" value="#{msgs.location}:" />
		<h:inputText  value="#{apartmentList.apartment.location}" id="location" required="true" immediate="true"  />
 
P

Phoe

Gast
Sorry für das verspätete Lebenszeichen. Bin zurzeit in Osteuropa unterwegs und hier ist das mit der I-net-Anbindung noch nicht ganz so...ausgereift. ^^

Ich versuche gleich mal, deine Vorschläge umzusetzen. Sollte das nicht auf Anhieb klappen, werd' ich wohl die Quick'n'Dirty - Variante bei meinem Dozenten einreichen und anschließend weiterforschen. Abgabefrist ist in 3 Tagen und da ich gerade online bin, muss ich die Daten jetzt hochladen.

Vielen Dank!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
P For-Schleife mit JSTL über ArrayList Web Tier 8
K Servlet + JSP: JSP-Seite ein Array/ArrayList überliefern vom Controller-Servlet Web Tier 8
N Struts 1.1 - Arraylist einzelnes Element ausgeben - Sessionattribute weitergeben Web Tier 3
V Bild aus ArrayList via h:graphicImage anzeigen lassen Web Tier 4
A [JSF 2.0] Ausgabe aus Schleife bzw. einer ArrayList Web Tier 9
S Random aus ArrayList Web Tier 2
G [JAVA / JSP] ArrayList in JSTL foreach verarbeiten Web Tier 4
L Validation über ManagedBeans Web Tier 7
K Internationalisierung über Properties Datei Web Tier 6
S Ich brauche Buchempfehlung über JSP und Servlet Web Tier 2
M JSF Actions über Methodenrückgabe? Web Tier 3
P JSP: Liste in Bean über Session aufbauen Web Tier 6
E JSF Applikation läuft nicht über Tomcat Web Tier 3
M Velocity - Dropdown-Felder über Macro generieren Web Tier 4
M Ton wiedergabe über jsp-Seite Web Tier 2
R Datenbankzugriff über JSP mit JDBC connector ! Web Tier 2
G JSF h:form Tag Login über j_security_check und weiterleiten Web Tier 5
R Array oder Listen einlesen mit JSF über javaserverpage Web Tier 2
G Dateiupload über JSF? Web Tier 5
G Überblick über Web-Technologien Web Tier 2
M Authentifizierung über PhaseListener je nach Seite Web Tier 11
A ice:inputText Converter Problem Web Tier 2
B JSF --- Auf InputText per JS zugreifen Web Tier 4
B JSF --- Inputtext readonly Web Tier 2
M Focus auf inputText setzten Web Tier 2
J <h:inputText> autosize? Web Tier 2
K Anfängerfrage in JSF: <h:inputText> aus Managed Bean ansprechen Web Tier 6
G JSP/JSF Inputtext rerender wenn Value geändert wird Web Tier 2
F a4j support und h:inputText Web Tier 5
A JSF-Ctrl h:inputText Problem mit Umlauten Web Tier 4

Ähnliche Java Themen

Neue Themen


Oben