Suchen mit Go und jQuery

Suchfeld

Die Suche mit zwei Eingabefeldern ist als Form innerhalb des <nav> Elements realisiert und mit Bootstrap Styles für reaktives Verhalten formatiert.

{{define "finder"}}
<div style="margin: 5px">
    <nav role="navigation" class="navbar navbar-default">
            <a href="/logout" class="navbar-brand navbar-right">
                <span class="sr-only">Logout</span>
                <span class="glyphicon glyphicon-off" style="margin-right: 5 px"></span>
                &nbsp;
            </a>
            <div class="navbar-header">
                <button type="button" data-target="#navbarCollapse" data-toggle="collapse" class="navbar-toggle">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
            </div>
            <div id="navbarCollapse" class="collapse navbar-collapse">
                <form role="search" class="navbar-form navbar-left">
                    {{template "csrf" . }}
                    <div class="form-group">
                        <input id="search1" type="text" placeholder="LastName" class="form-control" style="margin: 2px 0px;">
                        <input id="search2" type="text" placeholder="FirstName" class="form-control" style="margin: 2px 0px;">
                        <button id="find" type="button" class="btn btn-default" style="margin: 2px 0px;">
                            <span class="sr-only">Find</span>
                            <span class="glyphicon glyphicon-search"></span>
                        </button>
                        <div id="qapps" class="form-group" style="margin: 2px 0px;">
                            <select id="noresult" class="form-control" style="width: 16em;" disabled="disabled">
                                <option value="0">----------</option>
                            </select>
                        </div>
                    </div>
                </form>
        </div>
    </nav>
</div>
{{end}}
66
Das Template zum Cross Site Request Forgery (csrf) Schutz enthält ein hidden field mit einem kryptografischen Schlüssel, der von dem CSRF Filter ausgewertet wird.
70 – 73
Die Button Action wird beim Laden in den Browser per JavaScript gesetzt (s.u.)
75 – 77
Das Select Element wird nach Ausführung einer Suche mit den Ergebnissen nachgeladen.

Find Button Action

JavaScript im Browser

Die Aktion bei einem Click auf den Find Button wird (neben weiteren Initialisierungen) in der Initialisierungsfunktion $(document).ready(function(){ … }  in der JavaScript Datei work.js bestimmt.

    $(document).ready(function(){
        // bind function to #find button:
        $("#find").click(defaultFind);
        // bind function to tab selection event
        $('a[data-toggle="tab"]').on('shown.bs.tab', tabSwitchHandler);
        $('#do-cancellation').click(true, onCancellationRadioClick);
        $('#undo-cancellation').click(false, onCancellationRadioClick);
    });

    // default finder function for find button clicks
    // send query fields to server and load response into div #qapps
    function defaultFind() {
        var search1 = $("input#search1").val()
        var search2 = $("input#search2").val()
        var csrfid = $("input#csrf_id_find").val()
        var findUrl;
        if(typeof(finderValues[actTab]) !== 'undefined') {
            findUrl = finderValues[actTab].findUrl;
            $("#qapps").load(findUrl, {lastname: search1, firstname: search2, csrf_token: csrfid,
                action: actTab, flag: actTab === 'cancellation' ? searchFlag : ''},
                showSelect);
        }
    }
33
defaultFind() wird an das Click-Ereignis des #find Buttons gebunden.
47, 48
Die Service-URL für die aktuell aktive Tab-Seite wird bestimmt. Details dazu sind im Zusammenhang mit den Tab-Seiten beschrieben.
49-51
Die $.load() Funktion von jQuery wird aufgerufen: „Load data from the server and place the returned HTML into the matched element.“ Als zweiter Parameter wird eine Map übergeben, die serverseitig als Request Parameter gelesen werden kann. Die Go Handler Funktion unter der angegebenen URL liefert ein HTML Fragment, das in das Element mit der id „#qapps“ eingefügt wird. Das sollte also ein <select> Element mit allen <option> Elementen sein, die den Suchergebnissen entsprechen.
49
Nach Laden des HTML Fragments wird die function showSelect() aufgerufen. Diese wird zusammen mit den Tab Seiten beschrieben.
Go Handler Funktion

Eine typische Handler Funktion für die Suche ist FindApplicants( … ) . Andere Suchfunktionen sind aktuell im Beispiel nicht implementiert. Wir betrachten hier nur die für die Suche relevanten Zeilen.

// handler function that executes a database search for applicants and
// returns an html fragment for a select box.
func FindApplicant(w http.ResponseWriter, r *http.Request) {
	l := r.Header["Accept-Language"]
	getKyr := transcription.UsesKyrillic(l)
	r.ParseForm()
	lastName := html.EscapeString(r.PostFormValue("lastname"))
	firstName := html.EscapeString(r.PostFormValue("firstname"))
	action := html.EscapeString(r.PostFormValue("action"))
	flag := html.EscapeString(r.PostFormValue("flag"))
	enrol := action == "enrol"
	active := flag == ""
	applicants := findApplicants(lastName, firstName, enrol, active)
	view.Views().ExecuteTemplate(w, "qresult", applicantResultList(applicants, getKyr))
}
33
Vor jeder Auswertung der Request Parameter wird ParseForm aufgerufen, um die Request Parameter als PostFormValues bereitzustellen.
34, 35
Die Werte für die Suche werden aus dem Request als PostFormValue gelesen. Der Aufruf von EscapeString mit den gelesenen Werte ist eine extrem wichtige Sicherheitsmaßnahme, die verhindert, dass ausführbarer Code über ein Eingabefeld in den Server geschmuggelt und dort ausgeführt wird.
40
findApplicants( … ) liefert eine Liste von Applicant Objekten, die mit den Suchparametern gefunden wurden. Implizit wird immer das SQL Wildcard Symbol % an die Suchstrings angehängt, so dass er reicht, den Namensanfang einzugeben.
41
Die Funktion applicantResultList( … ) bereitet die gefundene Liste für die Verwendung im Go Template „qresult“ auf. Für die Ergebnisliste werden nur Vorname, Nachname und ID gebraucht.

Die eigentliche Suche wird in der Funktion findApplicants() in work.go durchgeführt.

// find applicants based on lastname and/or firstname. Per default, a wildcard search
// character (%) is appended to the search strings and query uses LIKE condition.
// Search is performed also in transcription fields
// ln, fn:      lastname, firstname search strings
// enrol:       true -> searching from the enrol use case for new applicants
// active:      true -> active applicant, not cancelled
func findApplicants(ln, fn string, enrol bool, active bool) (apps []model.Applicant) {
	var qs string
	if enrol {
		// query for newly registered applicants
		qs = "applicant_data.enrolled_at <'1900-01-01'"
	} else {
		// query for enrolled applicants
		qs = "applicant_data.enrolled_at > '" +
			time.Now().Format("2006") + "-01-01'"
	}
	db := model.Db()
	if active {
		// query for active applicants
		db.Preload("Data").
			Joins("INNER JOIN applicant_data ON applicants.id = applicant_data.applicant_id").
			Where("applicant_data.deleted_at IS NULL").
			Where(qs).
			Where("applicant_data.last_name like ? OR applicant_data.last_name_tx like ?",
			ln + "%", ln + "%").
			Where("applicant_data.first_name like ? OR applicant_data.first_name_tx like ?",
			fn + "%", fn + "%").
			Find(&apps)
	} else {
		// query for deleted applicants
		db.Unscoped().Preload("Data").
			Where("applicants.deleted_at IS NOT NULL").
			Joins("INNER JOIN applicant_data ON applicants.id = applicant_data.applicant_id").
			Where("applicant_data.deleted_at IS NULL").
			Where(qs).
			Where("applicant_data.last_name like ?", ln + "%").
			Where("applicant_data.first_name like ?", fn + "%").
			Find(&apps)
	}
	return
}
73, 76
Bewerber unterscheiden sich von immatrikulierten Studenten durch das enrolled_at Datum.
84-92, 95-102
Queries werden mit den Gorm Funktionen schrittweise aufgebaut und mit Find() ausgeführt.
95
Nach exmatrikulierten (d.h. gelöschten) Studenten muss mit Unscoped() gesucht werden, da sie in der Datenbank als gelöscht markiert sind.
Template zur Anzeige

Mit dem kleinen Template „qresult“ lässt sich sehr einfach aus der Ergebnis-Liste der HTML-Code für die Anzeige erzeugen.

{{define "qresult"}}
<select id="sresult" class="form-control" style="width: 16em;" onchange="showSelect()">
    {{range .}}
    <option value="{{.id}}">{{.lastname}}, {{.firstname}}</option>
    {{else}}
    <option value="0">not found</option>
    {{end}}
</select>
{{end}}
87
<select> Element mit vorbesetzter Event Handler Funktion, die auf das change Event reagiert. Dies wird ausgelöst, wenn eine andere Option ausgewählt wird, per Maus, Tastatur, … .
89
Nachname, Vorname wird angezeigt, die ID kann per JavaScript abgefragt werden oder wird mit den Formulardaten zum Server geschickt.
91
Suche lieferte keine Ergebnisse.

Das Ergebnis wird in den Browser geladen.

Ergebnis der Suche im Browser
Ergebnis der Suche im Browser

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.