JSF: h:dataTable / p:DataGrid : Pagination und alphabetisch springen

F.S.WhiTeY

Bekanntes Mitglied
Moin ihr Lieben,

Ich hatte vor ein paar tagen im WebTier diesen Post abgesetzt:

http://www.java-forum.org/web-tier/140090-h-datatable-p-komponente-pagination-buchstaben.html

Bezugnehmend dazu, möchte ich nun meine Lösung präsentieren, da ich im Web weder auf Englisch noch auf Deutsch einen Passenden Beitrag gefunden habe wie man soetwas umsetzen könnte.

Was wollte ich denn Eigentlich umsetzen? Nun wenn man es genau nimmt, eine Normale Pagination mit "Zurück" und "Weiter", sowie die Sprungfunktion nach Buchstaben wie Outlook sie in seinen Kontakten hat. Wie das ganze ( Ohne ins Design eingebunden zu sein) aussieht, könnt ihr im Anhang sehen.

Die von mir implementiert Umsetzung ist noch ein wenig "roh" oder "brutal" wenn man so will, es kann sicherlich noch Einiges optimiert werden.

Desweiteren benutze ich Primefaces DataGrid. Der vorteil dabei ist, dass ich mich bei Primefaces nicht weiter um den Ajax-Support kümmern muss. Eure Umsetzung für einen normalen h:dataTable müsste dann dementsprechend umgebaut / erweitert werden.

Nun zur Umsetzung.

1. Elemente zählen.


jeh nach dem wie eure Datenstruktur aussieht, ist das Zählen von Elementen einfacher oder schwerer.
Ich bekomme einfach eine Liste mit Adressen. Diese Liste muss ich "durchzählen" oder aufsplitten.

Denn wir müssen wissen, wie viele Elemente in den jeweiligen Untermengen ( 'A', 'B', 'C',...'Z','Zahlen+Sonderzeichen' ) enthalten sind.

Dieses "durchzählen" habe ich recht brutal durch einen verdammt langen Switch-Case gelöst. Lasst euch durch diesen Snipped nicht entmutigen, es ist der "unschönste" bei der ganzen sache.

Code 1: Elemente Zählen

Java:
public class AddressHandler{

//Die Liste in die wir unsere Zählung abspeichern, könnte auch ein Array sein.
private final List<Integer> addressCount = new ArrayList<Integer>();

..
..

private void countAddresses() {

       //Da wir eine Liste benutzen, müssen wir erstmal vorinitialisieren.
       //Hier zeigt sich, das ein Array eventuell besser wäre :D
       // Liste an der Stelle 0 ist A und Stelle 26 sind Zahlen und Sonderzeichen
       //Das wird dann dementsprechend hochgezählt.

        for (char c = 'A'; c <= 'Z' + 1; c++) {

            addressCount.add(0);

        }

        //Wir Itterieren über alle Adressen und schauen uns den ersten Buchstaben des Nachnamen an
        // Ergo -> ich sortiere nach Nachnamen. 

        for (InstitutionOrPrivateAddress a : addresses) {
                         
            //Gib mir den ersten Buchstaben des Nachnamen
            switch (a.getNachname().charAt(0)) {

                 //Wenn erster Buchstabe 'A' -> A um eins in der liste hochzählen.
                case 'A':
                    addressCount.set(0, addressCount.get(0) + 1);
                    break;
                //!!! WICHTIG: Ich zähle umlaute zu dem jehweiligen buchstaben 
                // ALSO: Ä gehört zu A
                case 'Ä':
                    addressCount.set(0, addressCount.get(0) + 1);
                    break;
                case 'B':
                    addressCount.set(1, addressCount.get(1) + 1);
                    break;
                case 'C':
                    addressCount.set(2, addressCount.get(2) + 1);
                    break;
                    ... 
                    ...
                    ...
                    ...
                case 'X':
                    addressCount.set(23, addressCount.get(23) + 1);
                    break;
                case 'Y':
                    addressCount.set(24, addressCount.get(24) + 1);
                    break;
                case 'Z':
                    addressCount.set(25, addressCount.get(25) + 1);
                    break;


                //Das ganze nochmal für lowercase 
                //Man kann sich ja auch mal verschrieben haben ;) 
                case 'a':
                    addressCount.set(0, addressCount.get(0) + 1);
                    break;
                case 'ä':
                    addressCount.set(0, addressCount.get(0) + 1);
                    break;
                case 'b':
                    addressCount.set(1, addressCount.get(1) + 1);
                    break;
                case 'c':
                    addressCount.set(2, addressCount.get(2) + 1);
                    break;
                    ... 
                    ...
                    ...
                    ...
                case 'y':
                    addressCount.set(24, addressCount.get(24) + 1);
                    break;
                case 'z':
                    addressCount.set(25, addressCount.get(25) + 1);
                    break;
                default:
                    addressCount.set(26, addressCount.get(26) + 1);
                    break;
            }//Ende Switch
        }//End For

        // Zu dieser Methode kommen wir gleich
        countRows();

    }


}

Das war ja schon mal ein Brocken an Code :D aber keine Angst, es wird nun chilliger.


2. Zeilen herausfinden.


Nun muss man sich überlegen, wohin man eigentlich sprinegn will.

Die Antwort: Zum ersten element der Untermenge 'A', 'B', 'C'... oder 'Z'. Das hat mich recht viel Nachdenken gekostet, bis ich mathematisch dahinter gekommen bin wie man das lösen kann. Wenn man es erstmal hat, ist es einfach.

Die alphabetisch größere Untermenge fängt nach dem letzten Elememt der vorangegangenen Menga an.

Also wenn 'A' = 5 Elemente dann fängt 'B' bei 6 an. Das müssen wir aufaddieren. Ein Schriftliches beispiel:

Wir wollen wissen wo C anfängt:

A=10 Elemente
B= 21 Elemente
C=3 Elemente

A + B = 31 --> C fängt bei 32 an und hört bei 34 auf. Wenn wir schon mal bei 34 sind, D fängt somit bei 35 an.


Code 2: Elemente aufaddieren.


Java:
//Die Methode wird nach dem "Durchzählen" aufgerufen, ihr erinnert euch?
private void countRows() {
       
        //Da ich die Methode auch nach einem Update aufrufem schmeiße ich erstmal alles raus.
        rowCount.clear();
        
        // A fängt IMMER bei Zeile 0 an
        rowCount.add(addressCount.get(0));
        
        int tmpI = addressCount.get(0);
        
        // Für alle gezählten Untermengen
        for (int i = 1; i < addressCount.size(); i++) {
            
            //Addiere bis nach hinten auf
            tmpI += addressCount.get(i);
            
            rowCount.add(tmpI);
            
        }

    }

So das wars mit der Vorbereitung. Nun können wir das in ner ManagedBean benuzen und es wird ein wenig Interessanter.


3. Setzen von "first" für die h:dataTable bzw. das p:dataGrid


h:datatable und p:dataGrid besitzen das Attribut first. Darüber wird angegeben in welcher Zeile man anfangen möchte. Wir schauen uns zuerst mal die JSF-Seite (xhtml) an.

Code 3: Die JSF Seite:
[XML]
<div style="hight: 60px; width: 1024px;">
<!-- ALLE BUTTONNS VON A bis Z -->
<h:panelGrid columns="13">
<p:commandButton value="A" action="#{institutionAdressBean.setFirstRow( '-1' )}" update="adrList" style="width: 50px;" ></p:commandButton>
<p:commandButton value="B" action="#{institutionAdressBean.setFirstRow( '0' )}" update="adrList" style="width: 50px;"></p:commandButton>
<p:commandButton value="C" action="#{institutionAdressBean.setFirstRow( '1' )}" update="adrList" style="width: 50px;"></p:commandButton>

<!--- UND SO WEITER --->

<p:commandButton value="X" action="#{institutionAdressBean.setFirstRow( '22' )}" update="adrList" style="width: 50px;"></p:commandButton>
<p:commandButton value="Y" action="#{institutionAdressBean.setFirstRow( '23' )}" update="adrList" style="width: 50px;"></p:commandButton>
<p:commandButton value="Z" action="#{institutionAdressBean.setFirstRow( '24' )}" update="adrList" style="width: 50px;"></p:commandButton>
</h:panelGrid>
</div>
<br/>

<!---WEITER UND ZURÜCK BUTTON--->
<center>
<div style="margin-left: auto; margin-right: auto;">
<p:commandButton value="Zurück" action="#{institutionAdressBean.setFirstRowPagination('-1')}" update="adrList" />
&nbsp;&nbsp;
<p:commandButton value="Weiter" action="#{institutionAdressBean.setFirstRowPagination('1')}" update="adrList" />
</div>
</center>
<br/>
<div style="width: 1024px;" >
<p:dataGrid id="adrList" var="adr" value="#{institutionAdressBean.selectetAddresses}" columns="3"
rows="12"
paginator="false"
style="min-width:1024px; min-height: 1200px;"
first="#{institutionAdressBean.firstRow}">

<p:column>
<p:panel header="#{adr.nachname}" style="text-align:left; max-width: 300px;">
<h:panelGrid columns="2" style="width:300px;">
Name: <h:eek:utputText value="#{adr.nachname}" />
Vorname: <h:eek:utputText value="#{adr.vorname}" />
Telefon: <h:eek:utputText value="#{adr.telefonGesch}" />
Handy:<h:eek:utputText value="#{adr.handyGesch}" />
</h:panelGrid>
</p:panel>
</p:column>

</p:dataGrid>

</div>
[/XML]


Wie wir sehen rufe ich jeweils eine Aktionmethode auf, wenn ich zu 'A', 'B' oder 'C' springen will und eine für weiter und zurück. Desweiteren "update" ich das DataGrid per AJAX und setze innerhalb der Bean das Attribut "first".

Vorweg sollte gesagt sein: Ich lasse 12 Elemente anzeigen, Daher die ->12<- bei Weiter und Zurück.

Dazu hier mal die ManagedBean:


Code 4: Die ManagedBean

Java:
@ManagedBean
@ViewScoped
public class InstitutionAdressBean {

    // Die Variable für das "first"
    private int firstRow = 0;

    //Einbinden der andern bean, mit den Adressen und den Counts per DI
    /** Creates a new instance of InstitutionAdressBean */
    public InstitutionAdressBean() {
    }
    @ManagedProperty(value = "#{global}")
    private GlobalAdressHandler globalAdressHandler;

    public void setGlobalAdressHandler(GlobalAdressHandler adressHandler) {
        this.globalAdressHandler = adressHandler;
    }

    //Gettermethode für die Adress-Liste. Wird vom DataGrid benötigt.
    // Unsere Adressen halt ;)
    public List<InstitutionOrPrivateAddress> getSelectetAddresses() {

        return globalAdressHandler.getAddresses();

    }
    
    //Getter für das "first"-Attribut
    public int getFirstRow() {
        return firstRow;
    }

    //Setter für A - Z
    public void setFirstRow(int firstRow) {
        // Wenn -1 dann wollen wir A haben und A fängt immer bei 0 an
        if (firstRow == -1) {
            this.firstRow = 0;
        } else {

            //Ansonsten gib uns die aufsummierten Zeilen zurück
            //Refferenz: CODE 2: Elemente aufaddieren

            this.firstRow = globalAdressHandler.getRowCount().get(firstRow);
        }
       
    }
    
 //Das setzen von "first" bei Weiter oder Zurück
    public void setFirstRowPagination(int firstRow){
        
        // -1 für Seite zurück
        if(firstRow == -1){
            
            if(this.firstRow>12){
                
            this.firstRow -= 12;
            
            }else{
                
                this.firstRow=0;
            }
        }//Ende Zurück
        
        //1 für eine Seite weiter
        if(firstRow == 1){
            
            if(this.firstRow < globalAdressHandler.getAddresses().size()-12){
                
                this.firstRow += 12;
                
            }else{
             
             
             double tmpD = globalAdressHandler.getAddresses().size() / 12;
             int tmpInt = (int)tmpD;
             this.firstRow = tmpInt +1;
                        
            }               
        }// Ende Weiter
        
    }
    
}



So das war es. Ich hoffe ihr könnt damit was anfangen. Ich würde mich freuen, wenn ihr das ganze auch noch diskutieren würdet. Man lernt ja nur dazu ;)

in diesem Sinne!

LG

David
 

Anhänge

  • pagination_Adressbuch.jpg
    pagination_Adressbuch.jpg
    48,6 KB · Aufrufe: 35
Zuletzt bearbeitet:

JCODA

Top Contributor
Ohne mich jetzt genauer mit dem eigentlichen "Problem" genauer zu beschäftigen, musste ich zumindest das hier:
Java:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Snippet {

	private static final Map<Character, Character> umlaute = new HashMap<>();
	static {
		umlaute.put('ö', 'o');
		umlaute.put('ä', 'a');
		umlaute.put('ü', 'u');
	}

	public static void main(String[] args) {
		int alph[] = new int[27];
		String[] s = { "A", "a", "?", "!", "ö", "Ö", "o", "Bloub" };
		for (String q : s) {
			char test = q.charAt(0);
			if (Character.isAlphabetic(test)) {
				test = Character.toLowerCase(test);
				if (umlaute.containsKey(test)) {
					test = umlaute.get(test);
				}
				alph[test - 'a']++;
			} else {
				alph[26]++;
			}
		}
		System.out.println(Arrays.toString(alph));

	}
}

posten, als ich deinen ersten Code gesehen hab. Vielleicht gehts sogar noch einfacher, wenn man die Umlaute anders behandeln darf.

Wir wollen wissen wo C anfängt:

A=10 Elemente
B= 21 Elemente
C=3 Elemente

A + B = 32 --> C fängt bei 33 an und hört bei 35 auf. Wenn wir schon mal bei 35 sind, D fängt somit bei 36 an.


Moment mal ... A+B = 31 und C fängt bei 32 an oder?
 
Zuletzt bearbeitet:

F.S.WhiTeY

Bekanntes Mitglied
Hey!

Moment mal ... A+B = 31 und C fängt bei 32 an oder?

Ja da hast du recht xD Ich editiere es mal nachträglich. Bin schon ein wenig durcheinander Heute ;)



Was deinen Code angeht: Ist auf jeden fall entspannter. Habe ja gesagt das das recht "roh" bzw. "brutal" ist. Auf jeden fall keine Finale Version. Ich denke mal ich werde deinen Snipped sogar so übernehmen bzw. ähnlich umsetzen.

Hatte nur nach einiger Zeit an rumrödeln, Suchen und Nachdenken keine lusst mehr etwas "schönes" zu produzieren :D


LG
 

Neue Themen


Oben