Table
Mit dem Table-Modul erstellst du übersichtliche und interaktive Tabellen, die sich perfekt für die Darstellung und Verwaltung deiner Daten eignen. Wie immer steht bei uns die Performance im Fokus, gefolgt von maximaler Flexibilität. Und auch über die vielen Features wirst du dich freuen, unter anderem:
- Gruppierungen in unendlich vielen Ebenen
- Nativ eingebaute Checkboxen - kein Zusatzmodul nötig
- Definiere Actions pro Zeile, pro Zelle oder beides!
- Class- und Style-Keys soweit das Auge reicht
Funktion und Aussehen
Unser Table-Modul besteht aus drei Hauptabschnitten: Dem Header, dem Body und dem Footer. Im Header werden die Spaltenbreiten definiert, die sich dank Subgrid-Dynamik auf Body und Footer übertragen. Ansonsten kannst du alle drei Abschnitte unabhängig voneinander nach deinen Vorstellungen stylen, sowohl mit dem Class-Key, als auch mit dem Style-Key. Mit dem Class-Key kannst du CSS-Klassen zuweisen, die von dir oder uns im Globalen Code definiert wurden. Damit kannst du kundenspezifische Stylings in Windeseile auf alle verbauten Tabellen anwenden. Zusätzlich kannst du den Style-Key für Inline-CSS nutzen. Beachte dabei, dass Inline-Styles immer Vorrang haben und die Class-Styles überschreiben, sofern sie dieselbe Property (z.B. background-color) betreffen.
Übersichtliche Gruppierung
Du kannst deine Daten in unendlich vielen Ebenen übersichtlich gruppieren und nach Bedarf ein- oder ausklappen. So können verschachtelte Ninox-Tabellen ganz einfach greifbar gemacht werden. Möchtest du z.B. eine Projekt-Verwaltung darstellen mit den Projekten auf 1. Ebene, Projektphasen in der 2. Ebene und den Aufgaben in diesen Projektphasen in der 3. Ebene? Kein Problem!
Die Gruppierungsfunktion macht deine Daten übersichtlich und leicht zugänglich. Du entscheidest selbst, welche Gruppen ein- oder ausgeklappt werden sollen. Mit dem "clickToCollapse"-Key kannst du festlegen, wo Benutzer klicken müssen, um Gruppen zu öffnen oder zu schließen. Zusätzlich gibt dir der Collapsable-Key die Möglichkeit, das Einklappen gleich für die komplette Gruppe zu deaktivieren. Außerdem hast du die Möglichkeit mit dem Collapsed-Key festzulegen, ob deine Nutzer die Gruppe beim ersten Laden ein- oder ausgeklappt sehen sollen.
Einfache Checklisten
Dank der nativ eingebauten Checkbox-Option kannst du schnell und unkompliziert Checklisten bauen. Du kannst sowohl einzelne Einträge oder gleich ganze Gruppen auswählen. Die verschiedenen Zustände der Gruppen-Checkboxen (ausgewählt, nicht ausgewählt, teilweise ausgewählt) geben dir einen schnellen Überblick über deine Auswahl. Du hast sogar die Möglichkeit, die jeweiligen Symbole selbst festzulegen, z.B. indem du unsere Material Symbols nutzt.
Optimale Performance
Mit unserer Table reizen wir die Grenzen der Ninox-Performance aus. Du kannst problemlos große Datenmengen darstellen und bearbeiten.
Nutzer-Interaktion
Wie die meisten unserer Module ist auch die Table mit dem Actions-Key ausgestattet. Lege vollkommen frei fest, welche und wie viele Actions du pro Zeile oder pro Zelle haben möchtest. Jede Action besteht aus einem auslösenden Trigger und einem Array von Scripts, die bei Auslösen des Triggers ausgeführt werden. Als Trigger können Klick, Mausbewegung und alle weiteren HTML Mouse Events eingesetzt werden. Je nach Anwendung können auch andere HTML Events funktionieren. Eine Liste solcher Events findest du beispielsweise hier. Weitere Infos zu Actions findest du in diesem Teil unserer Doku.
Modulcode
GIP_table({
uniqueId: "myUniqueName" + Nr
embedded: true
header: {
headerColumns: [{
columnWidth: "1fr"
value: *any*
}],
},
body: {
rowHeight: "40px"
rows: [{
columns: [{
value: *any*
}],
}],
},
})GIP_table({
uniqueId: "myUniqueName" + Nr
embedded: true
style: ""
header: {
style: ""
headerColumns: [{
style: ""
columnWidth: "1fr"
value: *any*
}],
},
body: {
style: ""
rowHeight: "40px"
rows: [{
style: ""
columns: [{
style: ""
hoverElement: {
style: ""
value: *any*
},
value: *any*
}],
}],
groups: [{
style: ""
groupColumns: [{
style: ""
hoverElement: {
style: ""
value: *any*
},
value: *any*
}],
rows: [{
style: ""
columns: [{
style: ""
hoverElement: {
style: ""
value: *any*
},
value: *any*
}],
}],
}],
},
})GIP_table({
uniqueId: "myUniqueName" + Nr
embedded: true
class: ""
style: ""
showCheckboxes: true
header: {
class: ""
style: ""
headerColumns: [{
style: ""
columnWidth: "1fr"
value: *any*
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
}],
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
},
body: {
class: ""
style: ""
rowHeight: "40px"
placeholder: {
style: ""
value: *any*
},
rows: [{
style: ""
columns: [{
style: ""
hoverElement: {
class: ""
style: ""
value: *any*
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
},
value: *any*
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
}],
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
}],
groups: [{
style: ""
groupColumns: [{
style: ""
hoverElement: {
class: ""
style: ""
value: *any*
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
},
value: *any*
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
}],
rows: [{
style: ""
columns: [{
style: ""
hoverElement: {
class: ""
style: ""
value: *any*
actions: [{
trigger: "click"
scripts: [{
type: [{}]
}],
}],
},
value: *any*
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
}],
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
}],
groups: [{
}],
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
}],
},
footer: {
class: ""
style: ""
footerColumns: [{
style: ""
value: *any*
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
}],
actions: [{
trigger: "click"
scripts: [{
type: ""
}],
}],
},
})GIP_table({
uniqueId: "",
embedded: {
height: "",
styleHtml: "",
styleStri: "",
},
class: "",
style: "",
showCheckboxes: {
iconSelected: true / *any*,
iconUnselected: true / *any*,
iconIndeterminate: true / *any*,
},
header: {
class: "",
style: "",
checkbox: {
recordId: "",
fieldId: "",
value: *any*,
},
headerColumns: [{
style: "",
columnWidth: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
body: {
class: "",
style: "",
rowHeight: "",
placeholder: {
style: "",
value: *any*,
},
rows: [{
style: "",
checkbox: {
recordId: "",
fieldId: "",
value: *any*,
},
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
groups: [{
collapseChildren: {
recordId: "",
fieldId: "",
value: *any*,
},
collapsible: true,
style: "",
checkbox: {
recordId: "",
fieldId: "",
value: *any*,
},
groupColumns: [{
clickToCollapse: true,
style: "",
hoverElement: {
class: "",
style: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
rows: [{
style: "",
checkbox: {
recordId: "",
fieldId: "",
value: *any*,
},
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
groups: [{
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
})html( raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "",
embedded: {
height: "",
styleHtml: "",
styleStri: "",
},
class: "",
style: "",
showCheckboxes: {
iconSelected: true / *any*,
iconUnselected: true / *any*,
iconIndeterminate: true / *any*,
},
header: {
class: "",
style: "",
checkbox: {
recordId: "",
fieldId: "",
value: *any*,
},
headerColumns: [{
style: "",
columnWidth: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
body: {
class: "",
style: "",
rowHeight: "",
placeholder: {
style: "",
value: *any*,
},
rows: [{
style: "",
checkbox: {
recordId: "",
fieldId: "",
value: *any*,
},
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
groups: [{
collapseChildren: {
recordId: "",
fieldId: "",
value: *any*,
},
collapsible: true,
style: "",
checkbox: {
recordId: "",
fieldId: "",
value: *any*,
},
groupColumns: [{
clickToCollapse: true,
style: "",
hoverElement: {
class: "",
style: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
rows: [{
style: "",
checkbox: {
recordId: "",
fieldId: "",
value: *any*,
},
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
groups: [{
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: *any*,
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
}],
actions: [{
trigger: "",
scripts: [{
type: "",
}],
}],
},
})
))Key-Table
Beispiele
Table: Basic ohne Gruppen
Beschreibung
Wir möchten eine Table bauen, in der wir Projekt-Aufgaben anzeigen mit Informationen zum Kunden, Projekt, Verantwortlichen, Priorität und Status der Aufgabe. Zusätzlich möchten wir bei Hover über Kunden, Projekte und Aufgaben jeweils einen Button angezeigt bekommen, mit dem wir in den entsprechenden Record springen können.
Um alle Daten in unserer Tabelle anzeigen zu können, benötigen wir 6 Spalten. Wir beginnen damit, im header diese 6 Spalten als headerColumns anzulegen, ihnen jeweils einen Spaltentitel (value) und eine Breite (columnWidth) zu geben. Diese festgelegte Breite wird automatisch auf alle Zellen der Spalte übertragen, inkl. dem Footer.
headerColumns: [{
style: "",
columnWidth: "3fr", // Die Spaltenbreite kann in Einheiten wie Fraction (fr) oder Pixel (px) angegeben werden. Wenn "auto" angegeben wird, passt sich die Spalte auf den Inhalt des Headers an.
value: "Kunde"
}, {
style: "",
columnWidth: "2fr",
value: "Projekt"
}, {
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
}Nach der Definition des Headers füllen wir den Body mit Daten. Wir vergeben eine feste rowHeight, sodass alle Zeilen der Tabelle eine einheitliche Höhe haben. Es kann ein Platzhalter definiert werden, für den Fall, dass keine Zeilen in der Tabelle angezeigt werden (z.B. weil es noch keine Aufgaben gibt oder weil mit den aktiven Filtern keine Aufgaben gefunden wurden).
Um den nun die Zeilen der Tabelle zu übergeben, nutzen wir den Key rows. Hierin iterieren wir durch unsere Aufgaben (projectTasks), um eine Zeile pro Aufgabe zu erhalten. Pro Zeile legen wir im Key columns die Zellen (Spalten) der Zeile fest. Jede Zelle besitzt einen value und kann ihr eigenes Styling haben. Außerdem legen wir für ausgewählte Spalten ein hoverElement fest. Dies ist ein Button, der beim Überfahren der Zelle mit der Maus erscheint. Als Action legen wir fest, dass der jeweilige Record des Kunden, des Projektes oder der Aufgabe geöffnet werden soll.
Wichtig ist, dass wir in den columns genauso viele Spalten definieren, wie wir headerCoulmns definiert haben. Ansonsten kommt es zu falschen Anzeigen und Umbrüchen der Spalten.
rows: for task in projectTasks do
task.{
style: "",
columns: [{
style: "",
hoverElement: if Projekte.Kunde then
{
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Projekte.Kunde.Nr
}]
}]
}
end,
value: Projekte.Kunde.Kundenname
}, {
style: "",
hoverElement: if Projekte then
{
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Projekte.Nr
}]
}]
}
end,
value: Projekte.Projektname
}, {
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
endSchließlich können wir auch für den Footer noch footerColumns festlegen, z.B. um die Anzahl der abgeschlossenen Aufgaben anzugeben. Die Nutzung des Footers ist optional, aber wenn er verwendet wird, muss auch hier auf die richtige Anzahl der Spalten geachtet werden.
footerColumns: [{
style: "",
value: cnt(unique(projectTasks.Projekte.Kunde)) + " Kunden"
}, {
style: "",
value: cnt(unique(projectTasks.Projekte)) + " Projekte"
}, {
style: "",
value: cnt(projectTasks) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectTasks.Verantwortlicher)) + " Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectTasks[number(Status) = 5]) + " Abgeschlossen"
}]Hinweis: Mit den richtigen CSS-Stylings können Zellen auch spaltenübergreifend zusammengefasst werden, z.B. um eine durchgehende Footer-Zeile zu erzeugen.
Code des Beispiels
let projectTasks := (select Aufgaben);
html(raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "OhneGruppierung" + Nr,
embedded: false,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "3fr",
value: "Kunde"
}, {
style: "",
columnWidth: "2fr",
value: "Projekt"
}, {
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
rows: for task in projectTasks do
task.{
style: "",
columns: [{
style: "",
hoverElement: if Projekte.Kunde then
{
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Projekte.Kunde.Nr
}]
}]
}
end,
value: Projekte.Kunde.Kundenname
}, {
style: "",
hoverElement: if Projekte then
{
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Projekte.Nr
}]
}]
}
end,
value: Projekte.Projektname
}, {
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(unique(projectTasks.Projekte.Kunde)) + " Kunden"
}, {
style: "",
value: cnt(unique(projectTasks.Projekte)) + " Projekte"
}, {
style: "",
value: cnt(projectTasks) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectTasks.Verantwortlicher)) + " Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectTasks[number(Status) = 5]) + " Abgeschlossen"
}]
}
})))let projectTasks := (select Aufgaben);
GIP_table({
uniqueId: "OhneGruppierung" + Nr,
embedded: true,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "3fr",
value: "Kunde"
}, {
style: "",
columnWidth: "2fr",
value: "Projekt"
}, {
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
rows: for task in projectTasks do
task.{
style: "",
columns: [{
style: "",
hoverElement: if Projekte.Kunde then
{
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Projekte.Kunde.Nr
}]
}]
}
end,
value: Projekte.Kunde.Kundenname
}, {
style: "",
hoverElement: if Projekte then
{
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Projekte.Nr
}]
}]
}
end,
value: Projekte.Projektname
}, {
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(unique(projectTasks.Projekte.Kunde)) + " Kunden"
}, {
style: "",
value: cnt(unique(projectTasks.Projekte)) + " Projekte"
}, {
style: "",
value: cnt(projectTasks) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectTasks.Verantwortlicher)) + " Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectTasks[number(Status) = 5]) + " Abgeschlossen"
}]
}
})Table: Eine Gruppenebene
Beschreibung
Wir möchten eine Table bauen, in der wir Projekt-Aufgaben anzeigen mit Informationen zum Kunden, Projekt, Verantwortlichen, Priorität und Status der Aufgabe. Für eine bessere Übersichtlichkeit möchten wir nach dem Kunden gruppieren.
Wie üblich beginnen wir damit, unseren header und die headerColumns zu definieren. Allerdings brauchen wir hier nur 5 Spalten, da wir unseren gruppierten Wert nicht in einer eigenen Spalte darstellen müssen.
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Projekt"
}, {
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
}Um unsere Gruppierung zu erhalten, verwenden wir im body den Key groups. Als Array of Objects übergeben wir an dieser Stelle alle Gruppen, also alle Kunden. Für jede Gruppe können wir Einstellungen (z.B. style, class,...), Gruppenspalten (groupColumns) und untergeordnete Zeilen (rows) übergeben.
Die Definition der groupColumns ist ähnlich zu den normalen Columns: Wir übergeben eine Array ob Objects, wobei jedes Object eine Spalte ist. Für jede Spalte der Gruppenzeilen können wir Stylings, den anzuzeigenden Wert und Actions festlegen. Im Gegensatz zu den normalen Columns besitzt groupColumns noch den Key clickToCollapse. Wenn beispielsweise ein Button in einer Spalte enthalten ist, können wir mit clickToCollapse: false verhindern, dass die Gruppe bei jeden Klick auf den Button ein-/aufklappt.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Kundenname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: [{}]
}
}Für die komplette Gruppe legen wir mit dem Key collapsible fest, ob sie überhaupt ein-/ausklappbar sein soll. Zusätzlich können wir mit collapseChildren einstellen, ob die Gruppe beim ersten Laden der Table ausgeklappt sein soll (mit einem Object statt einem Boolean-Wert könnte hier auch auf ein Ninox 'Ja / Nein'-Feld verwiesen werden).
In rows übergeben wir nun diejenigen Aufgaben, die den Projekten des aktuellen Kunden zugeordnet sind. Pro Aufgabe bauen wir nun wie üblich unsere Row-Objects.
Wichtig ist, dass wir in den groupColumns und columns genauso viele Spalten definieren, wie wir headerCoulmns definiert haben. Ansonsten kommt es zu falschen Anzeigen und Umbrüchen der Spalten.
Hinweis: Mit den richtigen CSS-Stylings können Zellen auch spaltenübergreifend zusammengefasst werden, z.B. um eine durchgehende Footer-Zeile zu erzeugen.
Code des Beispiels
let projectCostumers := (select Kunden);
html(raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "MitEinerGruppe" + Nr,
embedded: false,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Projekt"
}, {
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Kundenname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for task in Projekte.Aufgaben do
task.{
style: "",
columns: [{
style: "",
hoverElement: if Projekte then
{
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Projekte.Nr
}]
}]
}
end,
value: Projekte.Projektname
}, {
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(unique(projectCostumers.Projekte)) + " Projekte"
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})))let projectCostumers := (select Kunden);
GIP_table({
uniqueId: "MitEinerGruppe" + Nr,
embedded: true,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Projekt"
}, {
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Kundenname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for task in Projekte.Aufgaben do
task.{
style: "",
columns: [{
style: "",
hoverElement: if Projekte then
{
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Projekte.Nr
}]
}]
}
end,
value: Projekte.Projektname
}, {
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(unique(projectCostumers.Projekte)) + " Projekte"
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})Table: Mehrere Gruppenebenen
Beschreibung
Wir möchten eine Table bauen, in der wir Projekt-Aufgaben anzeigen mit Informationen zum Kunden, Projekt, Verantwortlichen, Priorität und Status der Aufgabe. Für eine bessere Übersichtlichkeit möchten wir nach dem Kunden und dem Projekt gruppieren.
Wir beginnen wie im Beispiel zur Gruppierung auf einer Ebene und erzeugen für jeden Kunden eine Gruppe im Array of Objects von groups.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{ }]
},
}Nun übergeben wir aber keine rows innerhalb der einzelnen Kundengruppen, sondern eine weitere Ebene an groups. In dieser Untergruppen-Ebene erzeugen wir für jedes Projekt des Kunden ein Object, das wir mit denselben Optionen einstellen können, wie die erste Gruppierungsebene.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{ }],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{ }]
},
},
}Erst in der Untergruppe übergeben wir jeweils die Projektaufgaben in rows.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{ }],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{ }],
rows: [{ }]
},
},
}Diese Verschachtelung von Gruppen und Untergruppen kann unendlich häufig fortgesetzt werden.
Code des Beispiels
let projectCostumers := (select Kunden);
html(raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "MehrereGruppenebenen" + Nr,
embedded: false,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Kundenname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Projektname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for task in project.Aufgaben do
task.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})))let projectCostumers := (select Kunden);
GIP_table({
uniqueId: "MehrereGruppenebenen" + Nr,
embedded: true,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Kundenname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Projektname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for task in project.Aufgaben do
task.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})Table: Spaltenübergreifende Zellen

Beschreibung
In einer Tabelle mit Gruppen möchten wir die Spalten der Gruppenzeilen zusammenfassen, um z.B. längere Texte darin darstellen zu können. Das folgende Vorgehen kann auch auf Footer übertragen werden.
Wir definieren wie üblich unsere 5 Spalten in den headerColumns, um für die Tabelle allgemeine Spaltenbreiten festzulegen. In den groupColumns definieren wir im Gegensatz zum normalen Vorgehen nun aber nur eine einzige Spalte (ein Object im Array). Dieser einzelnen Spalte geben wir folgendes Styling:
groupColumns: [{
style: "grid-column: 1 / -1; text-align: center;",
clickToCollapse: true,
value: let splitValue := split(Kundenname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Kundenname, 0, countSplitValue / 2), 50, "~") + rpad(slice(Kundenname, countSplitValue / 2, countSplitValue) + " ", 50, "~")
}],Der CSS-Style "grid-column" ermöglicht es uns, eine Spannweite der Zelle zu definieren. In diesem Beispiel übergeben wir den Startindex der Zelle ("1", da wir in der ersten Spalte starten möchten) und den Endpunkt der Zelle. Der Endpunkt "-1" bedeutet, dass die Zelle die komplette Breite einnehmen soll, unabhängig von der tatsächlich Spaltenanzahl.
Weitere Infos, wie man mit "grid-column" Spalten zusammenführen kannst, findest du beispielsweise hier.
Code des Beispiels
let projectCostumers := (select Kunden);
html(raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "SpaltenübergreifendeZellen" + Nr,
embedded: false,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "grid-column: 1 / -1; text-align: center;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: let splitValue := split(Kundenname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Kundenname, 0, countSplitValue / 2), 50, "~") +
rpad(slice(Kundenname, countSplitValue / 2, countSplitValue) + " ", 50, "~")
}],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "grid-column: 1 / -1; text-align: center;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: let splitValue := split(Projektname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Projektname, 0, countSplitValue / 2), 50, "+") +
rpad(slice(Projektname, countSplitValue / 2, countSplitValue) + " ", 50, "+")
}],
rows: for task in project.Aufgaben do
task.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})))let projectCostumers := (select Kunden);
GIP_table({
uniqueId: "SpaltenübergreifendeZellen" + Nr,
embedded: true,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "grid-column: 1 / -1; text-align: center;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: let splitValue := split(Kundenname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Kundenname, 0, countSplitValue / 2), 50, "~") +
rpad(slice(Kundenname, countSplitValue / 2, countSplitValue) + " ", 50, "~")
}],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "grid-column: 1 / -1; text-align: center;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: let splitValue := split(Projektname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Projektname, 0, countSplitValue / 2), 50, "+") +
rpad(slice(Projektname, countSplitValue / 2, countSplitValue) + " ", 50, "+")
}],
rows: for task in project.Aufgaben do
task.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})Table: Checkboxen
Beschreibung
Wir möchten in einer Tabelle Checkboxen einbauen, um einzelne Aufgaben, ganze Gruppen und die komplette Table abhaken zu können.
Um überhaupt Checkboxen in unserer Table anzeigen zu können müssen wir für den Key showCheckboxes entweder true oder ein Object mit selbst festgelegten Checkbox-Icons übergeben.
GIP_table({
uniqueId: "SpaltenübergreifendeZellen" + Nr,
embedded: false,
class: "",
style: "height: 500px;",
showCheckboxes: true,
})Danach können wir entscheiden, auf welchen Ebenen wir Checkboxen anzeigen möchten: Header, Groups, Rows. In allen Ebenen, in denen Checkboxen angezeigt werden sollen, übergeben wir den Key checkbox mit einem Object. Dieses Object enthält jeweils Informationen zu einem Ninox-Feld, das durch die Checkbox aktualisiert werden soll. In den Rows, also unseren Aufgaben, ist dies ein 'Ja / Nein'-Ninox-Feld, da Checkboxen für Rows nur zwei Stati haben können: true oder false.
rows: for task in project.Aufgaben do
task.{
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Toggle für Checkbox-Status"),
value: 'Toggle für Checkbox-Status'
},
}Für Gruppen und Header kommt noch ein weiterer Status hinzu: Indeterminate, der als Zahlwert "2" von der Table an Ninox übergeben wird. Dieser wird gesetzt, wenn nur ein Teil der Aufgaben abgehakt ist. Um diese drei Stati abbilden zu können, brauchen Groups, also unsere Kunden und Projekte, jeweils ein Text- oder Zahlfeld. Dasselbe gilt für den Header.
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Zahlfeld für Checkbox-Status"),
value: 'Zahlfeld für Checkbox-Status'
},
}header: {
class: "",
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Zahlfeld für Checkbox-Status"),
value: 'Zahlfeld für Checkbox-Status'
},
}Die Table hat nun Checkboxen und aktualisiert den Status in den jeweils verknüpften Ninox-Feldern. Allerdings möchten wir ja z.B. beim Aktualisieren eines Projektes auch alle dazugehörigen Aufgaben aktualisieren. Dieses Massenupdate muss Ninox-seitig gebaut werden, da hier die Performance mit dem Befehl "do as transaction" beschleunigt werden kann.
Für das Zahlfeld der Header Checkbox sieht der Trigger nach Änderung wie folgt aus:
do as transaction
let allCostumers := (select Kunden);
switch 'Zahlfeld für Checkbox-Status' do
case 0:
(
allCostumers.('Zahlfeld für Checkbox-Status' := 0);
allCostumers.Projekte.('Zahlfeld für Checkbox-Status' := 0);
allCostumers.Projekte.Aufgaben.('Toggle für Checkbox-Status' := 0)
)
case 1:
(
allCostumers.('Zahlfeld für Checkbox-Status' := 1);
allCostumers.Projekte.('Zahlfeld für Checkbox-Status' := 1);
allCostumers.Projekte.Aufgaben.('Toggle für Checkbox-Status' := 1)
)
case 2:
void
end
endTrigger nach Änderung auf Kunden-Ebene:
do as transaction
switch 'Zahlfeld für Checkbox-Status' do
case 0:
(
Projekte.('Zahlfeld für Checkbox-Status' := 0);
Projekte.Aufgaben.('Toggle für Checkbox-Status' := 0)
)
case 1:
(
Projekte.('Zahlfeld für Checkbox-Status' := 1);
Projekte.Aufgaben.('Toggle für Checkbox-Status' := 1)
)
case 2:
void
end
endTrigger nach Änderung auf Projekt-Ebene:
do as transaction
switch 'Zahlfeld für Checkbox-Status' do
case 0:
Aufgaben.('Toggle für Checkbox-Status' := 0)
case 1:
Aufgaben.('Toggle für Checkbox-Status' := 1)
case 2:
void
end
endCode des Beispiels
let projectCostumers := (select Kunden);
html(raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "SpaltenübergreifendeZellen" + Nr,
embedded: false,
class: "",
style: "height: 500px;",
showCheckboxes: true,
header: {
class: "",
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Zahlfeld für Checkbox-Status"),
value: 'Zahlfeld für Checkbox-Status'
},
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Zahlfeld für Checkbox-Status"),
value: 'Zahlfeld für Checkbox-Status'
},
groupColumns: [{
style: "grid-column: 2 / -1; text-align: center;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: let splitValue := split(Kundenname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Kundenname, 0, countSplitValue / 2), 50, "~") +
rpad(slice(Kundenname, countSplitValue / 2, countSplitValue) + " ", 50, "~")
}],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Zahlfeld für Checkbox-Status"),
value: 'Zahlfeld für Checkbox-Status'
},
groupColumns: [{
style: "grid-column: 2 / -1; text-align: center;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: let splitValue := split(Projektname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Projektname, 0, countSplitValue / 2), 50, "+") +
rpad(slice(Projektname, countSplitValue / 2, countSplitValue) + " ", 50, "+")
}],
rows: for task in project.Aufgaben do
task.{
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Toggle für Checkbox-Status"),
value: 'Toggle für Checkbox-Status'
},
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})))let projectCostumers := (select Kunden);
GIP_table({
uniqueId: "SpaltenübergreifendeZellen" + Nr,
embedded: true,
class: "",
style: "height: 500px;",
showCheckboxes: true,
header: {
class: "",
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Zahlfeld für Checkbox-Status"),
value: 'Zahlfeld für Checkbox-Status'
},
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Zahlfeld für Checkbox-Status"),
value: 'Zahlfeld für Checkbox-Status'
},
groupColumns: [{
style: "grid-column: 2 / -1; text-align: center;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: let splitValue := split(Kundenname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Kundenname, 0, countSplitValue / 2), 50, "~") +
rpad(slice(Kundenname, countSplitValue / 2, countSplitValue) + " ", 50, "~")
}],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Zahlfeld für Checkbox-Status"),
value: 'Zahlfeld für Checkbox-Status'
},
groupColumns: [{
style: "grid-column: 2 / -1; text-align: center;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: let splitValue := split(Projektname, "");
let countSplitValue := cnt(splitValue);
lpad(" " + slice(Projektname, 0, countSplitValue / 2), 50, "+") +
rpad(slice(Projektname, countSplitValue / 2, countSplitValue) + " ", 50, "+")
}],
rows: for task in project.Aufgaben do
task.{
style: "",
checkbox: {
recordId: Nr,
fieldId: fieldId(this, "Toggle für Checkbox-Status"),
value: 'Toggle für Checkbox-Status'
},
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})Table: Custom Styling

Beschreibung
Wir möchten statt dem Default-Styling der GIP-Table ein eigenes Styling festlegen, welches im globalen CSS definiert werden soll.
Wir legen zunächst eine Custom CSS-Class für die Table selbst fest, wo wir in diesem Beispiel eine feste Höhe vergeben. Danach folgen je nach Bedarf die Classen für Header, Body, Groups, Rows und Footer.
Interessant ist dabei, dass wir auch Attribute konditionell überschreiben können, z.B. die background-color der Rows. Zunächst legen wir eine allgemeine Hintergrundfarbe für Rows fest:
.customRow {
background-color: #FCFCFC;
}Da wir aber die Zeilen alternierend in einem helleren und einem dunkleren grau färben möchten definieren wir danach:
.customBody .GIPTableDummyRow[data-row-index]:nth-child(even) .GIPTableRow {
background-color: #F5F5F5;
}Hiermit geben wir an, dass wir in unserem customBody jede zweite Dummy-Row (geradzahlig) nehmen wollen. Für jede dieser ausgewählten Rows definieren wir nun die background-color in einem dunkleren grau.
Beachte bei der Definition immer die Reihenfolge von CSS-Klassen. Außerdem gilt auch für deine Custom Classes, dass Inline-Styles über den style-Key diese CSS-Deklarationen überschreiben können. Weitere Infos findest zu im Kapitel "Globaler CSS-Code".
Code des Beispiels
---
############### Füge den folgenden CSS-Code in die globale Funktion "GIP_customCSS()" ein und lade Ninox neu: ###############
---;
"
.customTable {
height: 500px;
}
.customHeader {
text-transform: uppercase;
background-color: #5F7EBA;
color: white;
}
.customBody {
border-color: white;
}
.customGroup {
font-weight: 600;
}
.customRow {
background-color: #FCFCFC;
}
.customBody .GIPTableDummyRow[data-row-index]:nth-child(even) .GIPTableRow {
background-color: #F5F5F5;
}
.customBody .GIPTableColumn {
padding-left: 12px;
padding-right: 12px;
}
.customFooter {
background-color: #5F7EBA;
color: white;
}
";
---
############### Füge den folgenden Code in dein Ninox-Formelfeld ein: ###############
---;
let projectCostumers := (select Kunden);
html(raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "SpaltenübergreifendeZellen" + Nr,
embedded: false,
class: "customTable",
style: "",
header: {
class: "customHeader",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "customBody",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "customGroup",
style: "",
groupColumns: [{
style: "grid-column: 1 / -1;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Kundenname
}],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "customGroup",
style: "",
groupColumns: [{
style: "grid-column: 1 / -1;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Projektname
}],
rows: for task in project.Aufgaben do
task.{
class: "customRow",
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "customFooter",
style: "",
footerColumns: [{
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})))---
############### Füge den folgenden CSS-Code in die globale Funktion "GIP_customCSS()" ein und lade Ninox neu: ###############
---;
"
.customTable {
height: 500px;
}
.customHeader {
text-transform: uppercase;
background-color: #5F7EBA;
color: white;
}
.customBody {
border-color: white;
}
.customGroup {
font-weight: 600;
}
.customRow {
background-color: #FCFCFC;
}
.customBody .GIPTableDummyRow[data-row-index]:nth-child(even) .GIPTableRow {
background-color: #F5F5F5;
}
.customBody .GIPTableColumn {
padding-left: 12px;
padding-right: 12px;
}
.customFooter {
background-color: #5F7EBA;
color: white;
}
";
---
############### Füge den folgenden Code in dein Ninox-Formelfeld ein: ###############
---;
let projectCostumers := (select Kunden);
GIP_table({
uniqueId: "SpaltenübergreifendeZellen" + Nr,
embedded: true,
class: "customTable",
style: "",
header: {
class: "customHeader",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "customBody",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: for costumer in projectCostumers do
costumer.{
collapseChildren: true,
collapsible: true,
class: "customGroup",
style: "",
groupColumns: [{
style: "grid-column: 1 / -1;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Kundenname
}],
groups: for project in costumer.Projekte do
project.{
collapseChildren: true,
collapsible: true,
class: "customGroup",
style: "",
groupColumns: [{
style: "grid-column: 1 / -1;",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Projektname
}],
rows: for task in project.Aufgaben do
task.{
class: "customRow",
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "customFooter",
style: "",
footerColumns: [{
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben) + " Aufgaben"
}, {
style: "",
value: cnt(unique(projectCostumers.Projekte.Aufgaben.Verantwortlicher)) +
" Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(projectCostumers.Projekte.Aufgaben[number(Status) = 5]) + " Abgeschlossen"
}]
}
})Table: Gruppierte und Ungruppierte Rows

Beschreibung
Wir haben eine Tabelle, in der wir Aufgaben auf erster Ebene nach Verantwortlichem und auf zweiter Ebene nach Projekt gruppieren. Allerdings gibt es auch Aufgaben ohne Verantwortlichen sowie Aufgaben mit Verantwortlichem, aber ohne Projekt.
Alle Aufgaben ohne Verantwortlichen stellen wir als normale Zeilen ohne Gruppierung dar. Dafür übergeben wir im body wie gewohnt den rows Key, wobei wir durch die Aufgaben ohne Verantwortlichen iterieren.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {...},
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [...]
}
end
}Zusätzlich übergeben wir im body auch den groups Key auf gleicher Ebene, wie die gerade angelegten rows. Auf dieser ersten Gruppenebene übergeben wir die Mitarbeiter / Verantwortlichen.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {...},
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [...]
}
end,
groups: for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...]
}
end
}Mit diesem Aufbau zeigen wir nun in der Table zuerst die nicht gruppierten Zeilen (Aufgaben ohne Verantwortlichen) an und danach die Gruppen (Verantwortliche).
Für den Inhalt der ersten Gruppierungsebene wiederholen wir das Vorgehen. Wir haben pro Verantwortlichem Aufgaben, die keinem Projekt zugeordnet sind, und Projekte, die die zweite Gruppierungsebene ergeben.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [...]
}
end,
groups: for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
rows: for taskNoProject in teamMember.Aufgaben[not Projekte] do
taskNoProject.{
style: "",
columns: [...]
}
end,
groups: for project in unique(teamMember.Aufgaben.Projekte) do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
}
end
}
end
}Schließlich übergeben wir für unsere zweite Gruppierungsebene auch noch die Aufgaben mit Projektzuordnung und Verantwortlichem.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [...]
}
end,
groups: for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
rows: for taskNoProject in teamMember.Aufgaben[not Projekte] do
taskNoProject.{
style: "",
columns: [...]
}
end,
groups: for project in unique(teamMember.Aufgaben.Projekte) do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
rows: for task in teamMember.Aufgaben[Projekte = project] do
task.{
style: "",
columns: [...]
}
end
}
end
}
end
}Code des Beispiels
let teamMembers := (select Mitarbeiter);
let allTasks := (select Aufgaben);
let tasksNotAssigned := allTasks[not Verantwortlicher];
html(raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "GruppierteUndUngruppierteRows" + Nr,
embedded: false,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end,
groups: for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Name
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for taskNoProject in teamMember.Aufgaben[not Projekte] do
taskNoProject.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end,
groups: for project in unique(teamMember.Aufgaben.Projekte) do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Projektname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for task in teamMember.Aufgaben[Projekte = project] do
task.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(allTasks) + " Aufgaben"
}, {
style: "",
value: cnt(unique(teamMembers)) + " Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(allTasks[number(Status) = 5]) + " Abgeschlossen"
}]
}
})))let teamMembers := (select Mitarbeiter);
let allTasks := (select Aufgaben);
let tasksNotAssigned := allTasks[not Verantwortlicher];
GIP_table({
uniqueId: "GruppierteUndUngruppierteRows" + Nr,
embedded: true,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end,
groups: for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Name
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for taskNoProject in teamMember.Aufgaben[not Projekte] do
taskNoProject.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end,
groups: for project in unique(teamMember.Aufgaben.Projekte) do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Projektname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for task in teamMember.Aufgaben[Projekte = project] do
task.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end
}
end
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(allTasks) + " Aufgaben"
}, {
style: "",
value: cnt(unique(teamMembers)) + " Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(allTasks[number(Status) = 5]) + " Abgeschlossen"
}]
}
})Table: Pseudogruppen

Beschreibung
Wir haben eine Tabelle, in der wir Aufgaben auf erster Ebene nach Verantwortlichem und auf zweiter Ebene nach Projekt gruppieren. Allerdings gibt es auch Aufgaben ohne Verantwortlichen sowie Aufgaben mit Verantwortlichem, aber ohne Projekt.
Alle Aufgaben ohne Verantwortlichen stellen wir in einer manuell angelegten Pseudogruppe dar. Dafür übergeben wir im body wie gewohnt den groups Key, bauen unser Array of Objects aber aus zwei Teilen auf. Zuerst bauen wir unsere Pseudogruppe auf, indem wir ein Array mit nur einem Object auf eine Variable schreiben. In dieser Pseudogruppe durchlaufen wir alle Aufgaben ohne Verantwortlichen und erstellen für diese die rows.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {...},
groups: let pseudoTeamMemberGroup := [{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [...]
}
end
}];
}Danach bauen wir in einer zweiten Variable die tatsächlich existierenden Gruppen auf, indem wir durch die Mitarbeiter iterieren. Nachdem wir nun sowohl die Pseudogruppe als ein Array mit einem Object, als auch die Verantwortlichen-Gruppen als Array mit vielen Objects angelegt haben, fassen wir diese mit dem Ninox-Befehl "array()" zusammen. Dadurch erhalten wir ein einziges Array ob Objects, für unseren groups-Key.
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {...},
groups: let pseudoTeamMemberGroup := [{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [...]
}
end
}];
let teamMemberGroups := for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
groups: [...]
}
end;
array(pseudoTeamMemberGroup, teamMemberGroups)
}Dieses Vorgehen, nicht zugeordnete Einträge in einer Pseudogruppe anzulegen, können wir nun gleich noch einmal verwenden. In den Verantwortlichen-Gruppen möchten wir nun nämlich auch noch nach Projekten gruppieren. Doch es kann auch Aufgaben geben, die zwar dem Verantwortlichen zugordnet sind, aber keinem Projekt haben. Daher erstellen wir innerhalb der Verantwortlichen wieder zur Definition der groups zuerst eine Variable für eine Pseudogruppe, bevor wir die tatsächlichen Projekt-Gruppen erstellen.
let teamMemberGroups := for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
groups: let pseudoProjectGroup := [{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
rows: for taskNoProject in teamMember.Aufgaben[not Projekte] do
taskNoProject.{
style: "",
columns: [...]
}
end
}];
let projectGroups := for project in unique(teamMember.Aufgaben.Projekte) do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [...],
rows: for task in teamMember.Aufgaben[Projekte = project] do
task.{
style: "",
columns: [...]
}
end
}
end;
array(pseudoProjectGroup, projectGroups)
}
end;Dieses Beispiel kann erweitert werden, um beliebig viele Pseudogruppen oder andere Arten von manuellen Gruppierungen zu erzeugen.
Code des Beispiels
let teamMembers := (select Mitarbeiter);
let allTasks := (select Aufgaben);
let tasksNotAssigned := allTasks[not Verantwortlicher];
html(raw(GIP_master({})) +
raw(GIP_table({
uniqueId: "PseudoGruppen" + Nr,
embedded: false,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: let pseudoTeamMemberGroup := [{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: "Aufgaben ohne Verantwortlichen"
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}];
let teamMemberGroups := for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Name
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
groups: let pseudoProjectGroup := [{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: "Aufgaben ohne Projekt-Zuweisung"
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for taskNoProject in teamMember.Aufgaben[not Projekte] do
taskNoProject.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}];
let projectGroups := for project in unique(teamMember.Aufgaben.Projekte) do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Projektname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for task in teamMember.Aufgaben[Projekte = project] do
task.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end;
array(pseudoProjectGroup, projectGroups)
}
end;
array(pseudoTeamMemberGroup, teamMemberGroups)
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(allTasks) + " Aufgaben"
}, {
style: "",
value: cnt(unique(teamMembers)) + " Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(allTasks[number(Status) = 5]) + " Abgeschlossen"
}]
}
})))let teamMembers := (select Mitarbeiter);
let allTasks := (select Aufgaben);
let tasksNotAssigned := allTasks[not Verantwortlicher];
GIP_table({
uniqueId: "PseudoGruppen" + Nr,
embedded: true,
class: "",
style: "height: 500px;",
header: {
class: "",
style: "",
headerColumns: [{
style: "",
columnWidth: "2fr",
value: "Aufgabe"
}, {
style: "",
columnWidth: "1fr",
value: "Verantwortlicher"
}, {
style: "",
columnWidth: "1fr",
value: "Priorität"
}, {
style: "",
columnWidth: "1fr",
value: "Status"
}]
},
body: {
class: "",
style: "",
rowHeight: "40px",
placeholder: {
style: "",
value: "Es wurden keine Daten gefunden, die auf die aktuellen Filter zutreffen."
},
groups: let pseudoTeamMemberGroup := [{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: "Aufgaben ohne Verantwortlichen"
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for taskNotAssigned in tasksNotAssigned do
taskNotAssigned.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}];
let teamMemberGroups := for teamMember in teamMembers do
teamMember.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Kunde öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Name
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
groups: let pseudoProjectGroup := [{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: "Aufgaben ohne Projekt-Zuweisung"
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for taskNoProject in teamMember.Aufgaben[not Projekte] do
taskNoProject.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}];
let projectGroups := for project in unique(teamMember.Aufgaben.Projekte) do
project.{
collapseChildren: true,
collapsible: true,
class: "",
style: "",
groupColumns: [{
style: "",
clickToCollapse: true,
hoverElement: {
class: "",
style: "",
value: "Projekt öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Projektname
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}, {
clickToCollapse: true,
style: "",
value: ""
}],
rows: for task in teamMember.Aufgaben[Projekte = project] do
task.{
style: "",
columns: [{
style: "",
hoverElement: {
class: "",
style: "",
value: "Aufgabe öffnen",
actions: [{
trigger: "click",
scripts: [{
type: "popup",
recordId: Nr
}]
}]
},
value: Bezeichnung
}, {
style: "",
value: Verantwortlicher.Name
}, {
style: "",
value: text('Priorität')
}, {
style: "",
value: Status.Bezeichnung
}]
}
end
}
end;
array(pseudoProjectGroup, projectGroups)
}
end;
array(pseudoTeamMemberGroup, teamMemberGroups)
},
footer: {
class: "",
style: "",
footerColumns: [{
style: "",
value: cnt(allTasks) + " Aufgaben"
}, {
style: "",
value: cnt(unique(teamMembers)) + " Verantwortliche"
}, {
style: "",
value: ""
}, {
style: "",
value: cnt(allTasks[number(Status) = 5]) + " Abgeschlossen"
}]
}
})