Prezentácia je k dispozícii tu.
Celý kód si napíšeme spolu, nasledujúce ukážky kódu sú tu v prípade, ak by niekto nestíhal, poprípade si to chcel pozrieť doma. :-)
Prvým krokom je spraviť si appku, ktorá nám vypíše Hello World!, aby sme v rýchlosti pochopili syntax Angularu :-)
Tento kód si napíšeme a vysvetlíme spolu.
Otvoríme príkazový riadok, nainštalujeme angular command line interface, vytvoríme nový projekt a otvoríme ho vo Visual studio code.
npm install -g @angular/cli
ng new my-first-angular
cd my-first-angular
code .
Otvoríme si terminál vo Visual studio code a server spustíme príkazom:
ng serve
Na základe zadania si vytvoríme komponenty, z ktorých sa bude skladať náš projekt.
ng generate component issuesform
ng generate component issuestable
ng generate component label
Vytvoríme si priečinok "model" a následne modely našich entít, ktoré budeme potrebovať:
							create new folder model
							create new file user.model.ts
							create new file label.model.ts
							create new file issue.model.ts
						
Namodelujeme si ich. Používateľ bude identifikovaný menom a emailom. user.model.ts:
export class UserModel {
	Id: number;
	Name: string;
	Email: string;
						
	constructor(Id: number, Name: string, Email: string) {
		this.Id = Id;
		this.Name = Name;
		this.Email = Email;
	}
}
							
							Každý label bude identifikovaný názvom, farbou písma a farbou pozadia. label.model.ts:
export class LabelModel {
	Id: number;
	Text: string;
	TextColor: string;
	BackgroundColor: string;
									
	constructor(Id: number, Text: string, TextColor: string, BackgroundColor: string) {
		this.Id = Id;
		this.Text = Text;
		this.TextColor = TextColor;
		this.BackgroundColor = BackgroundColor;
	}
}
									
							
						Každá issue(problém) bude identifikovaná dátumom a časom vytvorenia, textom, autorom, komu je daná požiadavka pridelená a tiež danými tagmi. issue.model.ts:
import { UserModel } from "./user.model";
import { LabelModel } from "./label.model";
import * as moment from "moment";
								
export class IssueModel {
	Id: number;
	Time: Date;
	Text: string;
	Author: UserModel;
	AssignedTo: UserModel;
	Labels: LabelModel[] = [];
								
	constructor(Id: number, Time: Date, Text: string, Author: UserModel, AssignedTo: UserModel, Labels: LabelModel[]) {
		this.Id = Id);
		this.Time = Time;
		this.Text = Text;
		this.Author = Author;
		this.AssignedTo = AssignedTo;
		this.Labels = Labels;
	}
								
	getTimeMoment() {
		return moment(this.Time);
	}
								
}
						
						Budeme tiež potrebovať service na prácu s našou internou "databázou" (nebudeme si ukazovať sql ani mongodb, podstatou projektu je ukázať si ako funguje angular).
ng generate service "model/issue"
Keďže pracujeme s interným úložiskom, je potrebné si nainicializovať potrebné hodnoty. Určite budeme potrebovať funkcie, ktoré nám vrátia všetky položky daného poľa. issue.service.ts:
import { Injectable } from '@angular/core';
import { IssueModel } from './issue.model';
import { UserModel } from './user.model';
import { LabelModel } from './label.model';
									
@Injectable({
	  providedIn: 'root'
})
									
export class IssueService {
							
	private _issueDatabase: IssueModel[] = null;
	private _issueDatabaseId: number = 2;
	private _userDatabase: UserModel[] = null;
	private _labelDatabase: LabelModel[] = null;
									
	constructor() {
		if (this._issueDatabase == null) {
							
		}
		this.initialize();
	}
							
	initialize() {
		this._userDatabase = [
			new UserModel(1, "Jozko", "jozko.mrkvicka@upjs.sk"), 
			new UserModel(2, "Evka", "eva.markova@upjs.sk"),
		];
		this._labelDatabase = [
			new LabelModel(1, "angular", "white", "red"),
			new LabelModel(2, "reactjs", "white", "blue"),
			new LabelModel(3, "python", "white", "green")
		];
		this._issueDatabase = [
			new IssueModel(1, new Date(), "Issue1", this.getUserById(1), this.getUserById(1), [
											this.getLabelById(1)]),
			new IssueModel(2, new Date(), "Issue2", this.getUserById(2), this.getUserById(1), [
											this.getLabelById(1),
											this.getLabelById(2)])
		];										
	}
									
	getLabelById(id: number): LabelModel {
		for (let label of this._labelDatabase) {
			if (label.Id == id) {
				return label;
			}
		}
		return null;
	}
									
									  
	getUserById(id: number): UserModel {
		for (let user of this._userDatabase) {
			if (user.Id == id) {
				return user;
			}
		}
		return null;
	}
									  
	getIssueById(id:number): IssueModel {
		for (let issue of this._issueDatabase) {
			if (issue.Id == id) {
				return issue;
			}
		}
		return null;
	}
									
	getAllUsers(): UserModel[] {
		return this._userDatabase;
	}
									
	getAllLabels(): LabelModel[] {
		return this._labelDatabase;
	}
									
	getAllIssues(): IssueModel[] {
		return this._issueDatabase;
	}
									  
	addOrChangeIssue(model: IssueModel): boolean {
		model.Id = ++this._issueDatabaseId;
		model.Time = new Date();
		this._issueDatabase.push(model);
		return true;
	}
}	
							
							Na vstupe očakávame label. label.component.ts:
import { Component, OnInit, Input } from '@angular/core';
import { LabelModel } from '../model/label.model';
								
@Component({
  selector: 'app-label',
  templateUrl: './label.component.html',
  styleUrls: ['./label.component.css']
})
								
export class LabelComponent implements OnInit {							
								 
	@Input() label: LabelModel;					
								  
	constructor() { }
								
	ngOnInit() {	  
	}
							
								
}							
						
						Dopredu si nadefinujeme ako bude vyzerať "výpis" konkrétneho labelu. label.component.html:
{{label.Text}} 
Do premennej issues si uložíme všetky issues. issuestable.component.ts:
import { Component, OnInit } from '@angular/core';
import { IssueModel } from '../model/issue.model';
import { IssueService } from '../model/issue.service';
import { Router } from '@angular/router';
								
@Component({
  selector: 'app-issuestable',
  templateUrl: './issuestable.component.html',
  styleUrls: ['./issuestable.component.css']
})
export class IssuestableComponent implements OnInit {
	protected issues: IssueModel[] = [];
	constructor(private issueService: IssueService, private router: Router) { }
	
	ngOnInit() {
		this.issues = this.issueService.getAllIssues();
		console.log(this.issues);
	}						
}
						
						V issuestable.component.html si naformátujeme výpis všetkých issues.
| ID | Čas | Názov | Autor | Pridelené | Tagy | Akcie | 
|---|---|---|---|---|---|---|
| {{issue.Id}} | {{issue.getTimeMoment().format("D.MMM.YYYY h:mm:ss")}} | {{issue.Text}} | {{issue.Author.Name}} | {{issue.AssignedTo.Name}} |  | 
Na vytvorenie úplne novej issue použijeme nový komponent. V podstate si ideme zadefinovať, akú bude mať funkcionalitu a ako bude vyzerať issue formulár. issuesform.component.ts:
								
import { Component, OnInit } from '@angular/core';
import { IssueModel } from '../model/issue.model';
import { IssueService } from '../model/issue.service';
import { LabelModel } from '../model/label.model';
import { UserModel } from '../model/user.model';
import { ActivatedRoute, Router } from '@angular/router';								
@Component({
  selector: 'app-issuesform',
  templateUrl: './issuesform.component.html',
  styleUrls: ['./issuesform.component.css']
})
export class IssuesformComponent implements OnInit {								
	protected model: IssueModel = new IssueModel();
	protected labels: LabelModel[];
	protected users: UserModel[];
	protected modelLabelsAssigns: {};
								
	constructor(private route: ActivatedRoute, private router: Router, private issueService: IssueService) {
	}
								
	ngOnInit() {
		let id = this.route.snapshot.paramMap.get('id');
		this.labels = this.issueService.getAllLabels();
		this.users = this.issueService.getAllUsers();
		this.modelLabelsAssigns = {};
		this.labels.forEach(label => {
			this.modelLabelsAssigns[label.Id] = false;
		});
								
	}
								
	onSubmit() {
		this.model.Labels = [];
		this.labels.forEach(label => {
			if (this.modelLabelsAssigns[label.Id]) {
				this.model.Labels.push(label);
			}
		});
									
		if (this.issueService.addOrChangeIssue(this.model)) {
			this.router.navigate(["/issues"]);
		}
	}								
}
						
						Tiež musíme prepísať html súbor. issuesform.component.html:
Issue formulár
V app-routing.module.ts si potrebujeme nadefinovať cesty.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';
import { IssuestableComponent } from './issuestable/issuestable.component';
import { IssuesformComponent } from './issuesform/issuesform.component';
								
const routes: Routes = [
  { path: 'issues', component: IssuestableComponent },
  { path: 'issues/create', component: IssuesformComponent },
  { path: '**', redirectTo: '/issues' },
];
								
@NgModule({
  imports: [CommonModule, RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
						
						app.component.html bude vyzerať nasledovne:
Do app.module.ts doplníme do imports FormModules.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { IssuesformComponent } from './issuesform/issuesform.component';
import { IssuestableComponent } from './issuestable/issuestable.component';
import { LabelComponent } from './label/label.component';
								
@NgModule({
  declarations: [
	AppComponent,
	IssuesformComponent,
	IssuestableComponent,
	LabelComponent
  ],
  imports: [
	BrowserModule,
	FormsModule,
	AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
						
Ale čo ak chceme editovať už pridanú issue? Do issuestable.component.ts pridáme:
editIssue(issue?: IssueModel) {							
	this.router.navigate(["/issues/edit", issue.Id]);						  
}
V issuesform.component.ts musíme v metóde ngOnInit() ošetriť, ak daná issue už existovala.
if (id) {
    this.model = this.issueService.getIssueById(Number(id));
    this.model.Labels.forEach(selected => {
        this.modelLabelsAssigns[selected.Id] = true;
    });
}
Pridáme tlačidlo do issuestable.component.html
Tiež je treba aktualizovať issue.service.ts:
addOrChangeIssue(model: IssueModel): boolean {
	if (model.Id != null) {
		let search = null;
		this._issueDatabase.forEach(item => {
			if (item.Id == model.Id) {
				search = item;
			}
		});
		let indexOf = this._issueDatabase.indexOf(search);
		this._issueDatabase.splice(indexOf, 1);
	} else {
		model.Id = ++this._issueDatabaseId;
		model.Time = new Date();
	}
	this._issueDatabase.push(model);
	return true;
}
Samozrejme nesmieme zabudnúť na nadefinovanie cesty.
 { path: 'issues/edit/:id', component: IssuesformComponent }
Ak chceme pekný dizajn, môžeme použiť knižnicu bootstrap.
npm install bootstrap
V súbore angular.json doplníme "styles" takto:
"styles": [ "node_modules/bootstrap/dist/css/bootstrap.min.css", "src/styles.css" ],
Do styles.css pridáme nasledujúci import:
@import '~bootstrap/dist/css/bootstrap.min.css';
Úlohy
- 
			Pridajte funkcionalitu vymazania issue (teda doplňte "delete" operáciu). 
 Hint: Na vymazanie z našej lokálnej "databázy" funguje príkaz nazov_db.splice(index_mazaneho, 1)
- Pridajte atribút priorita (pomocou modelu PriorityModel) pre issues s možnosťou výberu nízka, stredná a vysoká.