Material für Angular¶
Wir haben für unser frontend
in Übung 6 bereits Material als CSS-Framework verwendet und wollen dieses hier näher untersuchen, um Angular unter Zuhilfenahme von Material besser kennenzulernen. Zunächst nochmal, wie man einer existierenden Anwendung Material hinzufügt:
ng add @angular/material
In der angular.json
werden dann unter "projects"-->"architect"-->"build"
und unter "projects"-->"architect"-->"test"
die "styles"
wie folgt konfiguriert:
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.css"
],
Dabei hängt es jedoch davon ab, welches prebuilt-theme
Sie gewählt haben. Es gibt diese vier vorgefertigten Themen:
deeppurple-amber.css
indigo-pink.css
pink-bluegrey.css
purple-green.css
Einen Überblick über die unterschiedlichen Komponenten, die Material bereitstellt, finden Sie hier. Wir werden einige davon im folgenden verwenden.
Material Schematics¶
Ein großer Vorteil von Material ist, dass dieses Framework bereits sogenannte Schematics liefert, welche vorgefertigte Komponenten erstellen können. In Übung 6 haben wir bereits das Schema navigation
verwendet. Wir setzen auf die Lösung von Übung 6 auf.
Wir betrachten zunächst nochmal den aktuellen Stand dieser Lösung. Die app.component.html
sah so aus (je, nachdem, wie Sie Ihren Projekt-Prefix gewählt haben - hier jf
):
<jf-nav></jf-nav>
<h1>Tis is app</h1>
<mat-slider min="1" max="100" step="1" value="1"></mat-slider>
<router-outlet></router-outlet>
Es wird also zunächst die Navigationskomponente eingebunden und dann kommen noch eine Überschrift und ein Slider. In der Anwendung sieht man aber diese Sachen nicht mehr:
Das liegt daran, dass wir unsere Inhalte nun in die Navigationskomponente einfügen müssen. Die App-Komponente enthält nur noch den Komponentenselektor für die Navigationskomponente:
<jf-nav></jf-nav>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Das ist dann auch sichtbar:
Ehe wir uns mit dem Routing beschäftigen, erstellen wir zunächst noch zwei weitere Komponenten.
Table¶
Ein weiteres Schema, das wir verwenden wollen, ist das table
-Schema von Material. In unserem Ordner frontend2
rufen wir
ng generate @angular/material:table table
Um diese Komponente zu testen, binden wir sie zunächst in unsere nav
-Komponente ein (Beachten Sie, dass Ihr Prefix anders ist).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
Die Tabelle erscheint so:
Wir ändern die Tabelle und fügen eigene Daten ein, um uns mit der Komponente vertraut zu machen. Wir öffnen src/app/table/table-datasource.ts
. Je nach verwendeter Angular-Version sehen einige von Ihnen, dass diese Datei Fehler enthält. Die Funktionen sind rot unterstrichen. Das liegt daran, dass nun auch Funktionen typisiert werden müssen. Wir fügen die Rückgabetypen für die Funktionen deshalb zunächst ein:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
|
Wir werden die Komponente nun dahingehend ändern, dass unsere Mockup-Daten aus den vorherigen Übungen dargestellt werden, also diese hier:
mockup-data aus den vorherigen Übungen
[
{
id: 1,
forename: 'Catherine',
surname: 'Williams',
email: 'cwilliamsl@360.cn'
},
{
id: 2,
forename: 'Adam',
surname: 'Anderson',
email: 'aanderson8@google.fr'
},
{
id: 3,
forename: 'Susan',
surname: 'Andrews',
email: 'sandrewsn@google.co.jp'
},
{
id: 4,
forename: 'Catherine',
surname: 'Andrews',
email: 'candrewsp@noaa.gov'
},
{
id: 5,
forename: 'Alan',
surname: 'Bradley',
email: 'abradley1c@globo.com'
},
{
id: 6,
forename: 'Anne',
surname: 'Brooks',
email: 'abrooks16@bravesites.com'
},
{
id: 7,
forename: 'Russell',
surname: 'Brown',
email: 'rbrownq@nifty.com'
},
{
id: 8,
forename: 'Ryan',
surname: 'Burton',
email: 'rburton18@foxnews.com'
},
{
id: 9,
forename: 'Roy',
surname: 'Campbell',
email: 'rcampbell1@geocities.com'
},
{
id: 10,
forename: 'Russell',
surname: 'Campbell',
email: 'rcampbell17@eventbrite.com'
},
{
id: 11,
forename: 'Bonnie',
surname: 'Coleman',
email: 'bcoleman11@fc2.com'
},
{
id: 12,
forename: 'Ernest',
surname: 'Coleman',
email: 'ecoleman15@businessweek.com'
},
{
id: 13,
forename: 'Richard',
surname: 'Cruz',
email: 'rcruz7@unc.edu'
},
{
id: 14,
forename: 'Sean',
surname: 'Cruz',
email: 'scruz10@answers.com'
},
{
id: 15,
forename: 'Rebecca',
surname: 'Cunningham',
email: 'rcunninghamd@mac.com'
},
{
id: 16,
forename: 'Margaret',
surname: 'Evans',
email: 'mevansh@pcworld.com'
},
{
id: 17,
forename: 'Jeffrey',
surname: 'Ford',
email: 'jford14@cnet.com'
},
{
id: 18,
forename: 'Andrea',
surname: 'Gardner',
email: 'agardnerv@woothemes.com'
},
{
id: 19,
forename: 'Deborah',
surname: 'George',
email: 'dgeorge6@furl.net'
},
{
id: 20,
forename: 'Sean',
surname: 'Gibson',
email: 'sgibsony@alexa.com'
},
{
id: 21,
forename: 'Virginia',
surname: 'Graham',
email: 'vgrahamk@aol.com'
},
{
id: 22,
forename: 'Steven',
surname: 'Hamilton',
email: 'shamiltonu@state.tx.us'
},
{
id: 23,
forename: 'Virginia',
surname: 'Hawkins',
email: 'vhawkinsf@ehow.com'
},
{
id: 24,
forename: 'Edward',
surname: 'Hicks',
email: 'ehicksc@pcworld.com'
},
{
id: 25,
forename: 'Mark',
surname: 'Johnson',
email: 'mjohnsonj@hostgator.com'
},
{
id: 26,
forename: 'Ruth',
surname: 'Jordan',
email: 'rjordan1a@smugmug.com'
},
{
id: 27,
forename: 'Antonio',
surname: 'Kim',
email: 'akim4@odnoklassniki.ru'
},
{
id: 28,
forename: 'Jennifer',
surname: 'Marshall',
email: 'jmarshallt@gnu.org'
},
{
id: 29,
forename: 'Eric',
surname: 'Matthews',
email: 'ematthews5@independent.co.uk'
},
{
id: 30,
forename: 'Raymond',
surname: 'Mcdonald',
email: 'rmcdonald2@ihg.com'
},
{
id: 31,
forename: 'Eric',
surname: 'Miller',
email: 'emillere@creativecommons.org'
},
{
id: 32,
forename: 'Jonathan',
surname: 'Morales',
email: 'jmoralesa@ovh.net'
},
{
id: 33,
forename: 'Marie',
surname: 'Morgan',
email: 'mmorganb@cloudflare.com'
},
{
id: 34,
forename: 'Amanda',
surname: 'Nelson',
email: 'anelson13@indiatimes.com'
},
{
id: 35,
forename: 'Lisa',
surname: 'Olson',
email: 'lolsonr@telegraph.co.uk'
},
{
id: 36,
forename: 'Alice',
surname: 'Ortiz',
email: 'aortizw@histats.com'
},
{
id: 37,
forename: 'Peter',
surname: 'Phillips',
email: 'pphillipss@1688.com'
},
{
id: 38,
forename: 'Matthew',
surname: 'Porter',
email: 'mporter9@europa.eu'
},
{
id: 39,
forename: 'Tammy',
surname: 'Ray',
email: 'trayx@weather.com'
},
{
id: 40,
forename: 'Mark',
surname: 'Richardson',
email: 'mrichardson1d@ihg.com'
},
{
id: 41,
forename: 'Joan',
surname: 'Roberts',
email: 'jroberts12@alibaba.com'
},
{
id: 42,
forename: 'Kathleen',
surname: 'Rose',
email: 'kroseg@pinterest.com'
},
{
id: 43,
forename: 'Steve',
surname: 'Sanders',
email: 'ssanders1b@wikispaces.com'
},
{
id: 44,
forename: 'Shirley',
surname: 'Scott',
email: 'sscottm@macromedia.com'
},
{
id: 45,
forename: 'Lillian',
surname: 'Stephens',
email: 'lstephens19@hugedomains.com'
},
{
id: 46,
forename: 'Nicole',
surname: 'Thompson',
email: 'nthompson3@admin.ch'
},
{
id: 47,
forename: 'Marie',
surname: 'Thompson',
email: 'mthompsonz@yelp.com'
},
{
id: 48,
forename: 'Alan',
surname: 'Vasquez',
email: 'avasquezo@miibeian.gov.cn'
},
{
id: 49,
forename: 'Mildred',
surname: 'Watkins',
email: 'mwatkins0@miibeian.gov.cn'
},
{
id: 50,
forename: 'Eugene',
surname: 'Williams',
email: 'ewilliamsi@deliciousdays.com'
}
];
Ersetzen Sie das EXAMPLE_DATA
-Array in table-datasource.ts
durch obiges Array. Das Ersetzen der Arrays führt zu vielen Fehlern in table-datasource.ts
. Insbesondere sind z.B. die forename
-Eigenschaften rot unterstrichen. Das liegt daran, dass das interface TableItem
nicht mit dem Datenmodell der Mockup-Daten übereinstimmt. Wir müssen also das Interface wie folgt anpassen:
// TODO: Replace this with your own data model type
export interface TableItem {
id: number;
forename: string;
surname: string;
email: string;
}
Jetzt stimmt die Sortiermethode sort()
nicht mehr, da dort auf die Eigenschaft name
zugegriffen wird, diese Eigenschaft aber nicht mehr existiert. Wir passen also die Sortierfunktion entsprechend an:
private getSortedData(data: TableItem[]): TableItem[] {
if (!this.sort.active || this.sort.direction === '') {
return data;
}
return data.sort((a, b) => {
const isAsc = this.sort.direction === 'asc';
switch (this.sort.active) {
case 'forename': return compare(a.forename, b.forename, isAsc);
case 'surname': return compare(a.surname, b.surname, isAsc);
case 'email': return compare(a.email, b.email, isAsc);
case 'id': return compare(+a.id, +b.id, isAsc);
default: return 0;
}
});
}
Die Datei table-datasource.ts
sollte nun fehlerfrei sein. Nun passen wir noch die table.component.html
an. In ihr sind derzeit zwei Spalten für die Tabelle definiert, die id
-Spalte und die name
-Spalte (jeweils unter den entsprechenden HTML-Kommentaren). Kopieren Sie die name
-Spalte und fügern Sie sie zwei Mal in die table.component.html
ein. Passen Sie die Einträge entsprechend an. Die table.component.html
sollte dann so aussehen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
Nun passen wir nur noch die table.componen.ts
an. Dort müssen wir mitteilen, welche Eigenschaften unseres Datensatzes für die einzelnen Spalten der Tabelle verwendet und entsprechend dargestellt werden.
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
displayedColumns = ['id', 'forename', 'surname', 'email'];
Auch in der table.component.ts
sollten wir die Methoden noch typisieren. Beide Methoden sind void
-Methoden. Es handelt sich dabei um sogenannte Lifecycle-Hooks. Die ngOnInit()
-Funktion wird aufgerufen, wenn die Komponente initialisiert wird. Die ngAfterViewInit()
-Funktion wird aufgerufen, nachdem unsere View
, also die Tabellenansicht, initialisisert wurde. Die table.component.ts
sollte nun so aussehen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Unsere Seite sieht jetzt so aus:
Beachten Sie, dass Sie die Tabellenzeilen sortieren können. Neben den Spaltenüberschriften erscheinen bei Mouseover jeweils kleine Pfeile. Wenn Sie darauf klicken, werden die Tabellenzeilen entsprechend der Spaltensortierung angezeigt. Beachten Sie auch das Paginieren. Rechts unterhalb der Tabelle können Sie die Anzahl der Tabellenseite auf einer Seite ändern (siehe in table.component.html
die [pageSizeOptions]="[25, 50, 100, 250]
für den paginator
) und Sie können durch die Seiten blättern.
Ausblick: Wir haben die Daten hier clientseitig geladen, also nicht vom Server. Das werden wir später ändern. Zunächst schauen wir uns aber mal das Routing an.
Routing¶
Sie haben sich vielleicht schon gefragt, wozu der <router-outlet></router-outlet>
-Selektor da ist, der bei uns in der nav.component.html
enthalten ist. Wir wollen jetzt Komponenten über die URL ansprechen, also z.B. im Browser localhost:4200/table
angeben und nur unter dieser URL soll unsere Tabelle erscheinen. In Vorbereitung darauf, entfernen wir zunächst den Komponentenselektor für die Tabellen-Komponente aus der nav.component.html
:
25 26 27 28 29 30 31 32 |
|
Jetzt sieht man die Tabelle nicht mehr. Wir binden Sie aber gleich über den <router-outlet></router-outlet>
-Selektor wieder ein, wenn wir nämlich die URL localhost:4200/table
aufrufen. Dies wird Routing genannt. Um eine solche Route anzulegen, öffnen wir die Datei src/app/app-routing.module.ts
.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Geben Sie Zeile 6
ein und lassen Sie den Import (Zeile 3
) durch Ihre IDE erledigen. Wir haben uns eine neue Route angelegt. Wenn wir nun im Browser an die URL localhost:4200
noch /table
anhängen, wird die Tabellen-Komponente über den <router-outlet></router-outlet>
-Selektor eingebunden und angezeigt.
Öffnen Sie die nav.component.html
. Darin passen wir die Liste der Links (<mat-nav-list>
) an. Für Routen verwenden wir nicht href
, sondern routerLinks
. Die Liste soll so aussehen:
7 8 9 10 11 |
|
Nun können wir die Navigations-komponente verwenden, um zwischen den Routen /
und /table
zu wechseln.
Service¶
Derzeit sind unsere MockUp-Daten statisch in der table-datasource.ts
gespeichert. Wir wollen aber die Datenverwaltung (Speicherung und Bereitstellung) unabhängig von einer Komponente gestalten und allen Komponenten einen entsprechenden Service anbieten. Dazu erstellen wir uns einen solchen und legen diesen unter shared
ab, da sich alle Komponenten diesen Service teilen (können).
ng g service shared/data
Es entsteht der shared
-Ordner, der zwei Dateien enthält, die data.service.ts
und die data.service.spec.ts
. Letztere ist zum Testen und interessiert uns erstmal nicht. Schauen wir uns die data.service.ts
einmal an:
1 2 3 4 5 6 7 8 9 |
|
Für Services gibt es keine Lifecycle-Hooks. Wir finden hier deshalb auch keine ngOnInit()
-Methode. Während Komponenten den Decorator @Component()
aufweisen, wird für Services der Decorator @Injectable()
verwendet. Mit diesem Decorator geben wir an, dass der Service weitere Abhängigkeiten einbinden kann. Dies geschieht typischerweise über einen Parameter im Konstruktor - eine soganannte dependency injection (wenn über den Konstruktor, dann constructor injection). Auch wenn wir eine solche Abhängigkeit nicht einbinden, sollte der Decorator @Injectable()
stets für einen Service angegeben werden. Dies liegt daran, dass wir diesen Decorator um die providedIn
-Eigenschaft erweitern. Mit providedIn: 'root'
geben wir an, dass der Service allen Komponenten (im gesamten Root-Modul) zur Verfügung steht, er also von allen Komponenten genutzt werden kann. Bevor wir uns weiter um diesen Service kümmern, erstellen wir uns erst noch ein Datenmodell, auf das alle Komponenten zugreifen können.
Datenmodell¶
Derzeit haben wir unser Datenmodell ebenfalls statisch in der table-datasource.ts
als interface TableItem
definiert. Wir wollen das Interface auslagern (d.h. das Interface wird aus table-datasource.ts
gelöscht und in das neue data.ts
eingefügt) und ebenfalls allen Komponenten zur Verfügung stellen. Wir erstellen das Interface Data
(der Name ist sehr generisch gehalten - für Ihr eigenes Datenmodell sollten Sie einen besseren Namen wählen):
ng g interface shared/data
In die data.ts
tragen wir nun unser Datenmodell ein:
1 2 3 4 5 6 |
|
Wir wollen nun dieses Datenmodell verwenden und nicht mehr TableItem
. Dazu ändern wir nun zunächst die table-source.ts
. Löschen Sie dort am besten das gesamte interface TableItem
. Jetzt sehen Sie, an welchen Stellen Sie TableItem
durch Data
ersetzen müssen. Ersetzen Sie dann überall TableItem
durch Data
. Passen Sie beim Importieren des Interfaces auf, dass Sie das richtige importieren, Ihre IDE bietet Ihnen auch andere Importmöglichkeiten an (das liegt an dem generisch gewählten Namen). Die richtige import
-Anweisung ist: import { Data } from '../shared/data';
In der table.component.ts
muss an der Stelle @ViewChild(MatTable) table: MatTable<TableItem>;
ebenfalls TableItem
durch Data
ersetzt werden. In der Anweisung import { TableDataSource, TableItem } from './table-datasource';
entfernen Sie , TableItem
und fügen die Anweisung import { Data } from '../shared/data';
hinzu.
Unsere aktualisierten table-datasource.ts
und table.component.ts
sehen nun so aus:
aktualisierte Dateien
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
Jetzt funktioniert unsere Seite wieder. Unter localhost:4200/table
wird die Tabelle wieder korrekt angezeigt. Das Datenmodell wurde als eigenständiges interface
ausgelagert und kann von allen Komponenten verwendet werden. Wir werden nun unseren data.service
erweitern. Dazu öffnen wir die Datei data.service.ts
. Wir fügen eine Eigenschaft data
vom Typ Data[]
hinzu, also den interface
-Typ als Array. Bei der Erstellung des Services (im Konstruktor) werden die Daten eingelesen und data
initialisiert. Außerdem erstellen wir eine Funktion getAll()
, die das Data[]
zurückgibt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Nun lassen wir die table
-Komponente den Service nutzen. Dazu öffnen wir zunächst die table-datasource.ts
. Darin löschen wir die komplette Deklaration und Initialsisierung der const EXAMPLE_DATA: Data[]
, da wir die Daten ja jetzt über die getAll()
-Funktion des Services holen wollen. Dazu binden wir den Service per dependency injection in den Konstruktor von TableDatasource
ein und rufen in dem Konstruktor die getAll()
-Funktion des DataService
auf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Jetzt muss in der table.component.ts
nur noch der Aufruf des Konstruktors vom DataService
als Parmeter der TableDataSource()
-Konstruktors erfolgen:
23 24 25 |
|
Der DataService
muss dazu in table.component.ts
importiert werden. Lassen Sie das durch Ihre IDE erledigen. Nun werden die Daten über den Service bereitgestellt.
Success
Wir haben ein Datenmodell für unsere Daten erstellt und einen Service, der diese Daten über die getAll()
-Funktion zur Verfügung stellt. Wir werden den Service um weitere Funktionen erweitern und weitere Routen zu unserer Anwendung hinzufügen.
Parametrisierte Routen¶
Bis jetzt zeigen wir alle Daten zugleich in einer Tabelle an. Nun wollen wir auf einzelne Datensätze zugreifen. Dies soll über die id
aus unserem Datensatz geschehen. Wir wollen die einzelnen Datensätze über die URL localhost:4200/table/id
erreichen, wobei id
für eine Zahl steht.
Dazu erzeugen wir uns zunächst eine neue Komponente single
:
ng g c single
Diese Komponente soll ein Formular mit den Daten eines einzelnen Datensatzes aus unseren Mock-Up-Daten enthalten. Zunächst kümmern wir uns um die Route, über die die Single-Komponente erreichbar sein soll. Dazu öffnen wir die app-routing.module.ts
und erweitern das routes
-Array:
const routes: Routes = [
{ path: 'table', component: TableComponent },
{ path: 'table/:id', component: SingleComponent }
];
Die id
wird als Parameter für die Route vorgesehen, deshalb wird die Syntax :id
verwendet. Damit der entsprechende Wert für :id
aus der URL ausgelesen werden kann, benötigen wir in der Single-Komponente ein Objekt der Klasse ActivatedRoute
. Dieses Objekt binden wir per dependency injection in den Konstruktor der Single-Komponente ein und fragen die URL in der ngOnInit()
-Methode ab. Beachten Sie, wenn wir Objekte als private
in den Konstruktor injizieren, dann wird daraus eine Eigenschaft der Klasse, d.h. wir können route
und ds
mithilfe von this
in jeder Funktion der Klasse verwenden.:
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Wir lesen aus der URL den Parameter id
aus und speichern den Wert in this.id
(siehe Zeile 26
). Mit dem Wert rufen wir die getSingleId()
-Funktion aus dem DataService
auf. Diese Funktion gibt den Datensatz mit der entsprechenden id
zurück:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Für Arrow-Funktionen siehe hier. Die Single-Komponente
gestalten wir als Formular:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|
Das Formular ist als reaktives Formular definiert (im Gegensatz zu Template-Formularen). Wir verwenden den FormBuilder
und dessen group
-Funktion, um ein Formular zu erstellen. Das Formular selbst ist eine FormGroup
. Es enthält drei FormControl
-Elemente: forenameControl
, surnameControl
und emailControl
. Mithilfe der setValue()
-Funktion wird für diese Elemente ein value
gesetzt.
Unter dem Aufruf http://localhost:4200/table/11
sieht das Frontend jetzt z.B. so aus (Sie können natürlich auch den Slider und die Überschrift entfernen):
Success
Wir haben das Metrial-Schema für eine Tabelle ausprobiert, in der alle unsere Mockup-Daten angezeigt werden. In der Tablle kann nach allen Spalten sortiert werden. Außerdem ist die Tabelle paginiert. Wir haben Routing eingeführt, um über "sprechende" URLs auf unsere Komponenten zuzugreifen. Die Routen wurden auch mithife der IDs aus dem Datensatz parametrisiert. Wir haben ein Formular verwendet, um einen einzelnen Datensatz anzuzeigen. Die Verwaltung der Daten erfolgt über einen Service, der allen Komponenten zur Verfügung steht. Noch sind unsere Daten client-seitig gespeichert. Das soll in der nächsten Lektion geändert werden.