6 Tipps und Tricks für Views¶
6.1 Zugriff auf Abfrageergebnisse¶
Die Ergebnisse der Abfrage werden dem View als Model übergeben:
Model.Success
bool
war die Abfrage erfolgreich
Model.CountRecords
integer
Anzahl der zurückgegebenen Datensätze
Model.ElapsedMillisconds
integer
Abfragedauer in Millisekunden
Model.Records
Dictionary<string,object>[]
Enthält die Datensätze des Ergebnisses
ACHTUNG: da der Wert als Object-Typ gespeichert ist, sind keine direkten Vergleichsoperationen wie
record[‘NAME‘] == ‘Franz‘
möglich (Referenzvergleich). Hier muss über Equals verglichen werden, bspw."Franz".Equals(record["NAME"])
Model.QueryString
NameValueCollection
Enthält die Übergabeparameter des Aufrufes
Zugriff bspw. über:
Model.QueryString["Parametername"]
Auf die Datensätze im Dictionary kann über Linq zugegriffen werden:
Model.Records.Where(r=>String.IsNullOrEmpty(Model.QueryString["x"]) || Model.QueryString["x"].Equals(r["x_field"])).OrderBy(r=>r["data_field")
6.2 Hilfsfunktionen¶
Es gibt einige Hilfsfunktionen („DataLinqHelper“) mit denen zusätzliche Daten eingebunden oder etwa Formulare erzeugt werden können. Als Abkürzung kann statt „DataLinqHelper“ auch „DLH“ verwendet werden:
DataLinqHelper.IncludeView(url)
Zeigt in einem View Daten aus einem anderen an
Die URL ist ab der Endpunkt-Bezeichnung einzugeben:
DataLinqHelper.IncludeView(“ssg-sdet@proj-geb@proj-geb-bestand?GebaeudeId =E313049“)
DataLinqHelper.IncludeClickView(url,text)
siehe IncludeView, Inhalt wird erst bei Klick auf eine Schaltfläche geladen und angezeigt
der Parameter
text
bezieht sich auf die Beschriftung der Schaltfläche
DataLinqHelper.ResponsiveSwitcher()
Erzeugt eine Schaltfläche, die auf Klick alle HTML-Elemente mit der Klasse „responsive“ innerhalb der aktuellen Tabelle anzeigt bzw. wieder versteckt
DataLinqHelper.IncludeCombo(id, url, valueField, nameField)
Erzeugt eine Dropdown-Liste mit den Ergebnissen einer Abfrage
id
wird als HTML-Id-Attribut gesetzt
url
zeigt auf die Abfrage, deren Ergebnisse aufgelistet werden sollen
Bspw. ein Abfrage mit GroupBy
valueField
befüllt den Options-Wert mit dem angegeben Feld aus den Ergebnissen
nameField
befüllt den Options-Namen mit dem angegeben Feld aus den Ergebnissen
DLH.UrlEncode(text)
Kodiert den Text für die Verwendung in einer URL
Diese und weitere Hilfsfunktionen sind in der Hilfe zu DataLinqHelper mit Beispielen angeführt. Der Link zur Hilfe ist im Razor Markup Code Editor bei der Erstellung von Views rechts oben zu finden.
In den Views kann auch JavaScript in <script>
-Tags definiert werden. jQuery ist bereits eingebunden.
6.3 Beschränkung der Abfrageergebnisse - Query¶
Um die Serverlast und v.a. die Ladezeit beim Seitenaufbau am Client gering zu halten, ist es sinnvoll, die maximale Anzahl der Abfrageergebnisse und Felder zu beschränken:
bei API-Endpoints auf die WebGIS-Api ist diese Anzahl mit 1000 Datensätzen festgelegt, hier werden alle Spalten zurückgegeben, die im CMS definiert sind.
DB-Abfragen können im SQL-Statement beschränkt werden, bspw.
SELECT TOP 200 * …
bei MSSQL
SELECT * … LIMIT 200
bei MySQL, PostgreSQL
SELECT * … WHERE ROWNUM <= 200
bei Oracle
Idealerweise sollten die Ergebnisse durch eine Filterung mit (optionalen) Parametern (siehe Kapitel 3.2) soweit wie möglich eingeschränkt werden, um den AnwenderInnen eine schnellere Auswahl zu ermöglichen und nicht hunderte Zeilen durchsuchen zu müssen.
6.4 Beschränkung / Filtern der Abfrageergebnisse¶
Mithilfe von (optionalen) Parameter in den Queries lassen sich Abfrageergebnisse einschränken. In Views kann mit dem DataLinqHelper.FilterView
ein Filter eingebaut werden, der eine einfache und übersichtliche Eingabe / Auswahl dieser Filterparameter ermöglicht. Im Hintergrund werden die Übergabeparameter einfach an die Aufruf-URL (siehe Kapitel 4) angehängt.
Werden bereits beim Aufruf der View über die URL Filter- bzw. Sortierungsparameter definiert, so sind diese in der GUI bereits ausgefüllt bzw. gesetzt.
@DLH.FilterView(
"Filter",
new Dictionary<string, object>(){
{"STATUS", new { displayname="Status", source="endpoint@lov-status", valueField="VALUE", nameField="NAME", prependEmpty=true, multiple="multiple"} },
{"NACHNAME", new { displayname="Nachname" } },
{"GAS", new { displayname="Nur Gas betroffen", dataType=DataType.Checkbox } },
{"ERSTELLD_FROM", new { displayname="Datum von", dataType=DataType.Date } },
}
)
Ein Filterfeld kann als Auswahlliste definiert werden, dessen Werte aus einer anderen DataLinq-Query kommen, siehe Feld STATUS
. Bei Bedarf können auch mehrere
Listenwerte mit ;
getrennt übergeben werden (multiple=“multiple“
). Im SQL-Statement muss diese Aneinanderreihung wieder aufgesplittet werden. Bei einer REST-API Abfrage
muss im CMS die Abfrage-Methode des Suchfeldes als „In“ definiert werden.
Falls alle Filterfelder optional sind (also auch ohne eine einzige Einschränkung gesucht werden kann), kann man bei SQL-Statements eine allgemein gültige WHERE-Bedingung definieren und alle anderen optionalen Bedingungen mit „AND …“ anhängen.
Die Auswahllisten im Filter können kaskadierend sein, das heißt, ein Eingabefeld ist von einem anderen Feld abhängig. Immer wenn dieses Feld über die Auswahlliste geändert wird, ändert sich der Wert der abhängigen Auswahlliste(n).
@DLH.FilterView(
"Filter",
new Dictionary<string, object>(){
{"APP", new { displayname="App(s)", source="read@wlogging-apps", valueField="VALUE", nameField="VALUE", prependEmpty=true }},
{"TYPE", new { displayname="Type(s)", source="read@logging-types?APP=[APP]", valueField="VALUE", nameField="VALUE", prependEmpty=true } }
}
)
Das Feld TYPE
ist hier von der Auswahlliste APP
durch den Platzhalter [APP]
abhängig (APP=[APP]
). Immer wenn im Filter die Auswahl für APP
geändert wird,
wird die Auswahlliste TYPE
neu befüllt.
Die entsprechende Abfrage (hier Datenbankabfrage) muss natürlich den übergebenen Parameter APP
berücksichtigen, z.B.:
SELECT
DISTINCT(TYPE) as VALUE
FROM LOG_TABLE
WHERE 1=1
#if APP
AND APP = @APP
#endif
REST-API
dienst@cms/queries/abfrage?
#if STATUS
&status_in={{STATUS}}
#endif
#if NACHNAME
&nachname={{NACHNAME}}
#endif
#if ERSTELLD_FROM
&date_from={{ERSTELLD_FROM}}
#endif
#if GAS
&gas_betroffen=Ja*
#endif
#if _orderby
&_orderby={{_orderby}}
#endif
SQL
SELECT TOP(200)
status,
erstellt,
...
FROM tabelle
WHERE 0 = 0
#if STATUS
and status IN (SELECT value FROM STRING_SPLIT(@STATUS, ';'))
#endif
#if NACHNAME
and nachname = @NACHNAME
#endif
#if GAS
and gasanschluss = true
#endif
#if ERSTELLD_FROM
and erstellt >= CONVERT (date, @ERSTELLD_FROM, 104)
#endif
#if _orderby
ORDER BY @_orderby
#endif
In der View wird der Filter gerendert:
6.5 Sortieren der Abfrageergebnisse¶
Neben der Filterung steht mit DataLinqHelper.SortView ein weiterer Baustein zur Verfügung, mit dem die Datensätze im View per GUI sortiert werden können.
Die Sortier-Felder werden wie die Filterparameter im Hintergrund an der Aufruf-URL mit _orderby=…
angehängt.
Absteigende Sortierungen werden mit einem Minus („-“) vor dem Spaltennamen übergeben.
@DLH.SortView(
"Sortierung",
new Dictionary<string, object>(){
{"ERSTELLD", new { displayname="Zeitpunkt Erstellung" }},
{"STATUS", new { displayname="Status" }},
}
)
In der Query müssen diese Felder entgegengenommen werden, siehe Statements in Kapitel 5.4, in der View wird das Sortierwerkzeug gerendert:
6.6 Aktualisierung - Aufteilen von statischen und dynamischen Inhalten¶
Bei der (periodischen) Aktualisierung von Views werden alle Inhalte neu geladen. Falls in den Views CSS-Styles oder JavaScript vorkommt, wird dieses ebenfalls wieder dazu geladen und kann (v.a. bei JavaScript-Triggern) die Seite auf Dauer langsam machen (bis wieder eine „harte“ Aktualisierung mit F5, oder ein neuer Aufruf über die URL erfolgt).
Ein Beispiel für View-Inhalte, die häufig am selben Client aktualisiert werden, könnten Hydrographie-Daten – als eine Art Dashboard, das je Minute aktualisiert wird – sein.
In der „einfachen“ Form besteht diese Seite aus den tabellarischen Daten (HTML), Karte (JavaScript), CSS-Styles und JavaScript zum Anzeige der Diagramme – alles in einer einzigen View.
Wenn dieser View über den DLH.RefreshViewTicker
alle 60 Sekunden neu geladen wird, kommt jedes Mal JavaScript und CSS dazu – obwohl sich nur die tabellarischen Daten (HTML) ändern.
Hier macht es Sinn, den statischen, immer gleich bleibenden Code (JavaScript, CSS) vom dynamischen Teil (HTML) zu trennen und nur diesen neu zu laden. Immer wenn ein View neu geladen wurde, wird das Event „onpageloaded“ gefeuert. Auf dieses Ereignis kann im statischen Teil reagiert und bspw. Klick-Listener gesetzt werden:
<script>
webgis_datalinq.events.on('onpageloaded, function(channel, sender, args){
webgis.$(".TABDET.clickable tbody tr.extended-click").on("click", function() {
var id = $(this).attr("stoer_id");
...
6.7 Queries mit Domain-Übersetzung¶
Query-Domains kommen zur Anwendung, wenn in einer Tabelle ein Attribut eines Objektes mit einem Wert kodiert wird, bspw. 0 für „Wald“, 1 für „Wiese“ und 2 für „verbautes Gebiet“. In einer Tabellenansicht möchte man diese Werte nun mit den richtigen Namen übersetzen, um es den NutzerInnen verständlicher zu machen.
Im „Destination Field“ wird die Spaltenbezeichnung (kann auch ein Alias sein) jenes Feldes angegeben, das die kodierten Werte enthält. Unter „Query Id“ wird eine Lookup-Tabelle angegeben, die einerseits die kodierten Werte enthält und andererseits die Übersetzung. „Value-“ bzw. „Name Field“ geben die Spaltennamen dieser Lookup-Tabelle an. Wird im View des ursprünglichen Query auf das Feld (in der Grafik „STATUS_NAME“) zugegriffen, so wird nicht der kodierte Werte (bspw. 1) sondern die Übersetzung („Wiese“) ausgegeben.