Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[JSF] SelectOneMenu

Pagina: 1
Acties:

  • Standeman
  • Registratie: November 2000
  • Laatst online: 22:58

Standeman

Prutser 1e klasse

Topicstarter
Ik schaam me dood, maar ik krijg het als JSF noob maar niet voor elkaar! Volgens mij moet het ontzettend simpel zijn , maar om de een of andere reden lukt het me niet. Het gaat om de selectOneMenu tag in JSF waarbij ik een standaard waarde in de lijst wil selecteren.

Code in mijn backingBean
Java:
1
2
3
4
5
6
7
8
public List<SelectItem> getFooItems() {
  //Is een lijst met SelectItem objecten waarbij de value een foo instance is
  return fooItems; 
}

public SelectItem getFoo() {
  return this.foo; //is een bepaald SelectItem met een Foo als value
}


en in mijn JSF:

Java:
1
2
3
                <h:selectOneMenu  id="foobar" value="#{bean.foo}">
                    <f:selectItems value="#{bean.fooItems}"/>
                </h:selectOneMenu>


Maar om de een of andere reden wordt de juiste option niet geselecteerd. Heeft iemand enig idee wat ik fout doe?

The ships hung in the sky in much the same way that bricks don’t.


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Een geselecteerd item in een selectOne component is niet van het type SelectItem, maar van het type dat je IN je SelectItem stopt.

Bijv:
Java:
1
2
3
4
5
6
7
8
9
10
public List<SelectItem> getFooItems() {
  //Is een lijst met SelectItem objecten waarbij de value een foo instance is
  List<SelectItem> fooItems = new ArrayList<SelectItem>();
  fooItems.add(new SelectItem("hallohallohallo", "Dit is het label"));
  return fooItems; 
}

public String getFoo() {
  return this.foo;
}


XML:
1
2
3
<h:selectOneMenu  id="foobar" value="#{bean.foo}">
  <f:selectItems value="#{bean.fooItems}"/>
</h:selectOneMenu>


JSF zoekt simpelweg in de lijst met SelectItem objecten naar een SelectItem object waarvan de "value" property overeenkomt met de waarde die je in getFoo gespecificeerd hebt.

Met Strings werkt het doorgaans vrij eenvoudig, met complexere objecten kan het weleens lastiger zijn om aan 'equal' objecten te komen.

edit:

Oei ik zie nu dat je objecten van het type "Foo" zijn. Dan moet je in mijn verhaal "String" vervangen door "Foo".

[ Voor 6% gewijzigd door JKVA op 07-09-2007 15:26 ]

Fat Pizza's pizza, they are big and they are cheezy


  • Standeman
  • Registratie: November 2000
  • Laatst online: 22:58

Standeman

Prutser 1e klasse

Topicstarter
Dat had ik idd al geprobeerd, maar dat werkte niet.

Java:
1
2
3
4
5
6
7
8
9
10
11
public List<SelectItem> getFooItems() {
  List<SelectItem> fooItems = new ArrayList<SelectItem>();
  for (Foo foo : fooList) {
    fooItems.add(new SelectItem(foo, foo.getName()));
  }
  return fooItems; 
}

public foo getFoo() {
  return this.foo;
}


Zou het wel werken wanneer ik de equals() method implementeer in het Foo object. (De lijst met Foo's haal ik apart op uit de DB, dus ze zijn niet equal volgens de equals() method.)

Update:
Met het implementeren van de equals() methode werkt inderdaad wel.

[ Voor 7% gewijzigd door Standeman op 07-09-2007 16:22 ]

The ships hung in the sky in much the same way that bricks don’t.


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Standeman schreef op vrijdag 07 september 2007 @ 15:42:
Dat had ik idd al geprobeerd, maar dat werkte niet.

Java:
1
2
3
4
5
6
7
8
9
10
11
public List<SelectItem> getFooItems() {
  List<SelectItem> fooItems = new ArrayList<SelectItem>();
  for (Foo foo : fooList) {
    fooItems.add(new SelectItem(foo, foo.getName()));
  }
  return fooItems; 
}

public foo getFoo() {
  return this.foo;
}


Zou het wel werken wanneer ik de equals() method implementeer in het Foo object. (De lijst met Foo's haal ik apart op uit de DB, dus ze zijn equal volgens de equals() method.)
Dat lijkt me idd noodzakelijk, want anders wordt het een vergelijking op object identity en die zal in de meeste gevallen falen verwacht ik. (het werkt hooguit goed als je caching ofzo gebruikt binnen 1 JVM verwacht ik)

Fat Pizza's pizza, they are big and they are cheezy


  • Standeman
  • Registratie: November 2000
  • Laatst online: 22:58

Standeman

Prutser 1e klasse

Topicstarter
Nu bedenk ik me net. Hoe kan je het beste de equals methode implementeren. Op het moment kijk ik naar de primary key uit de DB die ook in Foo aanwezig is (return foo.getFooKey == this.fooKey) staat. Of is het beter alle velden in Foo te controleren?

[ Voor 14% gewijzigd door Standeman op 07-09-2007 16:26 ]

The ships hung in the sky in much the same way that bricks don’t.


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

De equals doet hier totaal niet toe. Alle in de HTML pagina gerenderde waarden zijn (uiteraard) van het String type, al dan niet indirect verkregen middels Object#toString(). Een selectOneMenu waarde van Foo herkent "mypackage.Foo@12345678" (of whatever jouw Foo#toString() eruitziet) natuurlijk niet als een Foo object. Kijk maar eens in de broncode. Als je <h:messages /> aan de form toevoegt, dan heb je een dikke kans dat je een "Conversion error" melding krijgt bij het submitten.

Er zijn 2 algemene manieren om dit probleem te verhelpen: zelf een Converter schrijven dat tussen Foo en String converteert en deze aan de selectOneMenu koppelen, óf een backing map onderhouden met Foo objecten en daaraan gekoppeld een unieke String key die dan in de selectOneMenu wordt gebruikt, waarmee je achteraf tijdens de actie het Foo object kunt terugvinden adhv de unieke String key.

[ Voor 25% gewijzigd door BalusC op 07-09-2007 18:41 ]


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

BalusC schreef op vrijdag 07 september 2007 @ 18:33:
De equals doet hier totaal niet toe. Alle in de HTML pagina gerenderde waarden zijn (uiteraard) van het String type, al dan niet indirect verkregen middels Object#toString(). Een selectOneMenu waarde van Foo herkent "mypackage.Foo@12345678" (of whatever jouw Foo#toString() eruitziet) natuurlijk niet als een Foo object. Kijk maar eens in de broncode. Als je <h:messages /> aan de form toevoegt, dan heb je een dikke kans dat je een "Conversion error" melding krijgt bij het submitten.

Er zijn 2 algemene manieren om dit probleem te verhelpen: zelf een Converter schrijven dat tussen Foo en String converteert en deze aan de selectOneMenu koppelen, óf een backing map onderhouden met Foo objecten en daaraan gekoppeld een unieke String key die dan in de selectOneMenu wordt gebruikt, waarmee je achteraf tijdens de actie het Foo object kunt terugvinden adhv de unieke String key.
Mja, ik denk idd dat je gelijk hebt. Ik werk de laatste tijd vrijwel alleen nog met Trinidad en die regelt conversie onder water. Dan hoef je niet constant Converters te schrijven.

Je kunt ook, afhankelijk van de hoeveelheid en het soort data, gewoon kiezen voor een Long datatype, namelijk het ID van het record. Je moet iets meer programmeren en de kans bestaat dat je meer database calls moet doen, maar het werkt verder prima. Het scheelt sowieso geheugen, vergeleken met het bijhouden van full-blown objecten.

offtopic:
@Standeman: Werk je nog steeds met IceFaces? Zo ja, een beetje tevreden?

[ Voor 3% gewijzigd door JKVA op 07-09-2007 20:17 ]

Fat Pizza's pizza, they are big and they are cheezy


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Ik heb ondertussen een blog entry over geschreven. Doe er je voordeel mee :)
http://balusc.blogspot.co...ts-in-hselectonemenu.html

  • Standeman
  • Registratie: November 2000
  • Laatst online: 22:58

Standeman

Prutser 1e klasse

Topicstarter
Ik ga even kijken naar je blog. Overigens vind ik het raar dat na de implementatie van equals() wel de goede waarde geselecteerd wordt in mijn select menu en daarvoor niet. Ik vermoedde dat de renderer van het component ging kijken of de objecten wel equal zouden zijn en dan het juiste element "selected" zou renderen.

offtopic:
Ja, maar in combinatie met Spring WebFlow werkte het niet (een hoop javascript errors en raar render gedrag) .
Verder ben ik er niet helemaal kapot van. Dat komt misschien ook omdat het nog een beetje klok-klepel verhaal voor me is wat betreft het kennen en kunnen van icefaces. (AJAX principes snap ik wel, maar ik zie nog niet helemaal hoe en waar ik het goed kan toepassen).

The ships hung in the sky in much the same way that bricks don’t.


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Heb je nog meer gedaan naast equals? Hier kijkt de JSF UISelectOne/UISelectMany helemaal niet naar. Ik heb het hier zelfs even snel uitgeprobeerd (de rest van de code is dezelfde als in de blog):
Java:
1
2
3
public boolean equals(Object obj) {
    return obj != null && obj instanceof Foo && key.equals(((Foo) obj).key);
}
Volgens debug wordt deze geeneens aangeroepen en het levert nog steeds een conversion error op wanneer ik Foo gebruik in selectItem zonder converters. Heb je niet toevallig eerst bij wijze van test de Foo vervangen door String en deze hierna niet teruggezet?

[ Voor 9% gewijzigd door BalusC op 11-09-2007 16:02 ]


  • Standeman
  • Registratie: November 2000
  • Laatst online: 22:58

Standeman

Prutser 1e klasse

Topicstarter
BalusC schreef op dinsdag 11 september 2007 @ 13:56:
Heb je nog meer gedaan naast equals? Hier kijkt de JSF UISelectOne/UISelectMany helemaal niet naar. Ik heb het hier zelfs even snel uitgeprobeerd (de rest van de code is dezelfde als in de blog):
Java:
1
2
3
public boolean equals(Object obj) {
    return obj != null && obj instanceof Foo && key.equals(((Foo) obj).key);
}
En deze levert nog steeds een conversion error op wanneer ik Foo gebruik in selectItem zonder converters. Heb je niet toevallig eerst bij wijze van test de Foo vervangen door String en deze hierna niet teruggezet?
Ik zie nu net dat toString() is geimplementeerd in het Foo object. Dit zal waarschijnlijk wel de oorzaak zijn dat het nu opeens wel werkt.

The ships hung in the sky in much the same way that bricks don’t.


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

Dat zal inderdaad werken als je de Foo type als SelectItem value hebt en een String type als selectedItem. Het was toch jouw bedoeling om de Foo type te gebruiken als selectedItem property?
Pagina: 1