Add editing/creating of ranks
parent
4c6f3dab78
commit
ec756028aa
|
@ -0,0 +1,3 @@
|
||||||
|
.form-control {
|
||||||
|
height: auto;
|
||||||
|
}
|
|
@ -12,7 +12,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<img src="resource/rank/{{rank._id}}.png" class="rank-list-preview">
|
<img src="{{imageSrc}}" class="rank-list-preview">
|
||||||
<span (click)="delete(); $event.stopPropagation()" title="Löschen" class="glyphicon glyphicon-trash trash"></span>
|
<span (click)="delete(); $event.stopPropagation()" title="Löschen" class="glyphicon glyphicon-trash trash"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ export class RankItemComponent {
|
||||||
|
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
rank: Rank;
|
rank: Rank;
|
||||||
|
imageSrc;
|
||||||
|
|
||||||
rankSelected = new EventEmitter();
|
rankSelected = new EventEmitter();
|
||||||
rankDelete = new EventEmitter();
|
rankDelete = new EventEmitter();
|
||||||
|
@ -22,6 +23,10 @@ export class RankItemComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.imageSrc = 'resource/rank/' + this.rank._id + '.png?' + Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
select() {
|
select() {
|
||||||
this.rankSelected.emit(this.rank._id)
|
this.rankSelected.emit(this.rank._id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,13 @@ export class RankListComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
openNewRankForm() {
|
openNewRankForm() {
|
||||||
|
this.selectedRankId = null;
|
||||||
this.router.navigate([{outlets: {'right': ['new']}}], {relativeTo: this.route});
|
this.router.navigate([{outlets: {'right': ['new']}}], {relativeTo: this.route});
|
||||||
}
|
}
|
||||||
|
|
||||||
selectRank(rankId: string | number) {
|
selectRank(rankId: string | number) {
|
||||||
this.selectedRankId = rankId;
|
this.selectedRankId = rankId;
|
||||||
this.router.navigate([{outlets: {'right': ['overview', rankId]}}], {relativeTo: this.route});
|
this.router.navigate([{outlets: {'right': ['new', rankId]}}], {relativeTo: this.route});
|
||||||
}
|
}
|
||||||
|
|
||||||
filterRanksByFraction(query = '', fractionFilter) {
|
filterRanksByFraction(query = '', fractionFilter) {
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
.preview-image {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
height: auto;
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
<form #form="ngForm" class="overview">
|
||||||
|
<h3 *ngIf="rank._id">Rang editieren</h3>
|
||||||
|
<h3 *ngIf="!rank._id">Neuen Rang hinzufügen</h3>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title">Name</label>
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
[(ngModel)]="rank.name"
|
||||||
|
name="title"
|
||||||
|
id="title"
|
||||||
|
required maxlength="50"/>
|
||||||
|
|
||||||
|
<show-error text="Name" path="title"></show-error>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="fraction">Fraktion</label>
|
||||||
|
<select id="fraction" name="fraction" class="form-control btn dropdown-toggle"
|
||||||
|
required
|
||||||
|
[(ngModel)]="rank.fraction">
|
||||||
|
<option value="OPFOR">CSAT</option>
|
||||||
|
<option value="BLUFOR">NATO</option>
|
||||||
|
</select>
|
||||||
|
<show-error text="Fraktion" path="fraction"></show-error>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="level">Stufe</label>
|
||||||
|
<input id="level" name="level" type="number" class="form-control btn dropdown-toggle"
|
||||||
|
[(ngModel)]="rank.level">
|
||||||
|
<show-error text="Stufe" path="level"></show-error>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="logo">Bild</label>
|
||||||
|
<input id="logo" name="logo" class="ui-button form-control" type="file"
|
||||||
|
accept="image/png"
|
||||||
|
#fileInput
|
||||||
|
(change)="fileChange($event)">
|
||||||
|
<span class="label label-bg label-danger center-block" style="font-size:small" *ngIf="showImageError">
|
||||||
|
Bild muss im PNG Format vorliegen
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<img class="preview-image" src="{{imagePreviewSrc}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="cancel"
|
||||||
|
(click)="cancel()"
|
||||||
|
class="btn btn-default">
|
||||||
|
Abbrechen
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button id="save"
|
||||||
|
(click)="saveRank(fileInput)"
|
||||||
|
class="btn btn-default"
|
||||||
|
[disabled]="!form.valid">
|
||||||
|
Squad speichern
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<span *ngIf="showSuccessLabel"
|
||||||
|
class="label label-success label-small"
|
||||||
|
style="margin-left: inherit">
|
||||||
|
Erfolgreich gespeichert
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</form>
|
|
@ -0,0 +1,105 @@
|
||||||
|
import {Component, ViewChild} from "@angular/core";
|
||||||
|
import {ActivatedRoute, Router} from "@angular/router";
|
||||||
|
import {NgForm} from "@angular/forms";
|
||||||
|
import {Rank} from "../../models/model-interfaces";
|
||||||
|
import {RankService} from "../../services/rank-service/rank.service";
|
||||||
|
import {Subscription} from "rxjs/Subscription";
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: './new-rank.component.html',
|
||||||
|
styleUrls: ['./new-rank.component.css', '../../style/new-entry-form.css']
|
||||||
|
})
|
||||||
|
export class CreateRankComponent {
|
||||||
|
|
||||||
|
subscription: Subscription;
|
||||||
|
|
||||||
|
rank: Rank = {name: '', fraction: '', level: 0};
|
||||||
|
|
||||||
|
fileList: FileList;
|
||||||
|
|
||||||
|
saved = false;
|
||||||
|
|
||||||
|
showImageError = false;
|
||||||
|
|
||||||
|
imagePreviewSrc;
|
||||||
|
|
||||||
|
showSuccessLabel = false;
|
||||||
|
|
||||||
|
@ViewChild(NgForm) form: NgForm;
|
||||||
|
|
||||||
|
constructor(private route: ActivatedRoute,
|
||||||
|
private router: Router,
|
||||||
|
private rankService : RankService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.subscription = this.route.params
|
||||||
|
.map(params => params['id'])
|
||||||
|
.filter(id => id != undefined)
|
||||||
|
.flatMap(id => this.rankService.getRank(id))
|
||||||
|
.subscribe(rank => {
|
||||||
|
this.rank = rank;
|
||||||
|
this.imagePreviewSrc = 'resource/rank/' + this.rank._id + '.png?' + Date.now();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
fileChange(event) {
|
||||||
|
if (!event.target.files[0].name.endsWith('.png')) {
|
||||||
|
this.showImageError = true;
|
||||||
|
this.fileList = undefined;
|
||||||
|
} else {
|
||||||
|
this.showImageError = false;
|
||||||
|
this.fileList = event.target.files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveRank(fileInput) {
|
||||||
|
let file: File;
|
||||||
|
if (!this.rank._id) {
|
||||||
|
if (this.fileList) {
|
||||||
|
file = this.fileList[0];
|
||||||
|
this.rankService.submitRank(this.rank, file)
|
||||||
|
.subscribe(rank => {
|
||||||
|
this.saved = true;
|
||||||
|
this.router.navigate(['..'], {relativeTo: this.route});
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return window.alert(`Bild ist ein Pflichtfeld`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.fileList) {
|
||||||
|
file = this.fileList[0];
|
||||||
|
}
|
||||||
|
delete this.rank['__v'];
|
||||||
|
this.rankService.submitRank(this.rank, file)
|
||||||
|
.subscribe(rank => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.imagePreviewSrc = 'resource/rank/' + this.rank._id + '.png?' + Date.now();
|
||||||
|
}, 300);
|
||||||
|
fileInput.value = '';
|
||||||
|
this.showSuccessLabel = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.showSuccessLabel = false;
|
||||||
|
}, 2000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.router.navigate([this.rank._id ? '../..' : '..'], {relativeTo: this.route});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
canDeactivate(): boolean {
|
||||||
|
if (this.saved || !this.form.dirty) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return window.confirm(`Ihr Formular besitzt ungespeicherte Änderungen, möchten Sie die Seite wirklich verlassen?`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,79 +0,0 @@
|
||||||
<div class="overview">
|
|
||||||
<h3 style="margin-bottom: 25px">Rang-Details
|
|
||||||
<span *ngIf="showSuccessLabel"
|
|
||||||
class="label label-success label-small"
|
|
||||||
style="margin-left: inherit">
|
|
||||||
Erfolgreich gespeichert
|
|
||||||
</span>
|
|
||||||
</h3>
|
|
||||||
<div *ngIf="rank">
|
|
||||||
<div class="col-xs-12">
|
|
||||||
|
|
||||||
|
|
||||||
<div class="div-table">
|
|
||||||
<div class="div-table-row">
|
|
||||||
<div class="div-table-col content-s">
|
|
||||||
<label>Name:</label>
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col content content-m">
|
|
||||||
{{rank.name}}
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col content-l">
|
|
||||||
<input class="form-control" width="250px" placeholder="Neuer Name" #newNameInput>
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col content-s">
|
|
||||||
<a class="pull-right btn btn-sm btn-block btn-default" (click)="update('name', newNameInput)">Bestätigen</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="div-table-row">
|
|
||||||
<div class="div-table-col content-s">
|
|
||||||
<label>Fraktion:</label>
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col fraction-opfor content-m" *ngIf="rank.fraction == 'OPFOR'">
|
|
||||||
CSAT
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col fraction-blufor content-m" *ngIf="rank.fraction == 'BLUFOR'">
|
|
||||||
NATO
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="div-table-row">
|
|
||||||
<div class="div-table-col content-s">
|
|
||||||
<label>Stufe:</label>
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col content content-m">
|
|
||||||
{{rank.level}}
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
<div class="div-table">
|
|
||||||
<div class="div-table-row">
|
|
||||||
<div class="div-table-col content-s">
|
|
||||||
<label>Bild:</label>
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col content-m-flex">
|
|
||||||
<img src="{{imagePreview}}">
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col content-l">
|
|
||||||
<label class="control-label">Neues Logo</label>
|
|
||||||
<input class="form-control" type="file" accept="image/png" #newGraphicInput (change)="fileChange($event)">
|
|
||||||
<span class="label label-bg label-danger center-block" style="font-size:small" *ngIf="showImageError">
|
|
||||||
Bild muss im PNG Format vorliegen
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="div-table-col content-s">
|
|
||||||
<label> </label>
|
|
||||||
<a class="pull-right btn btn-sm btn-block btn-default" (click)="updateGraphic(newGraphicInput)">Bestätigen</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,86 +0,0 @@
|
||||||
import {Component} from "@angular/core";
|
|
||||||
import {ActivatedRoute} from "@angular/router";
|
|
||||||
import {Rank} from "../../models/model-interfaces";
|
|
||||||
import {RankService} from "../../services/rank-service/rank.service";
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
templateUrl: './rank-overview.component.html',
|
|
||||||
styleUrls: ['./rank-overview.component.css', '../../style/overview.css'],
|
|
||||||
})
|
|
||||||
export class RankOverviewComponent {
|
|
||||||
|
|
||||||
showSuccessLabel = false;
|
|
||||||
|
|
||||||
showImageError = false;
|
|
||||||
|
|
||||||
rank: Rank;
|
|
||||||
|
|
||||||
fileList: FileList;
|
|
||||||
|
|
||||||
imagePreview;
|
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
|
||||||
private rankService: RankService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.route.params.subscribe((params) => {
|
|
||||||
this.rankService.getRank(params['id']).subscribe(rank => {
|
|
||||||
this.rank = rank;
|
|
||||||
this.imagePreview = 'resource/rank/' + rank._id + '.png?' + Date.now();
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* register change on file input and save to local fileList
|
|
||||||
* @param event
|
|
||||||
*/
|
|
||||||
fileChange(event) {
|
|
||||||
if (!event.target.files[0].name.endsWith('.png')) {
|
|
||||||
this.showImageError = true;
|
|
||||||
this.fileList = undefined;
|
|
||||||
} else {
|
|
||||||
this.showImageError = false;
|
|
||||||
this.fileList = event.target.files;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
update(attrName, inputField) {
|
|
||||||
const inputValue = inputField.value;
|
|
||||||
if (inputValue.length > 0 && this.rank[attrName] !== inputValue) {
|
|
||||||
const updateObject = {_id: this.rank._id};
|
|
||||||
updateObject[attrName] = inputValue;
|
|
||||||
this.rankService.updateRank(updateObject)
|
|
||||||
.subscribe(rank => {
|
|
||||||
this.rank = rank;
|
|
||||||
inputField.value = '';
|
|
||||||
this.showSuccessLabel = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.showSuccessLabel = false;
|
|
||||||
}, 2000)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateGraphic(fileInput) {
|
|
||||||
if (this.fileList && this.fileList.length > 0) {
|
|
||||||
let file: File = this.fileList[0];
|
|
||||||
this.rankService.updateRankGraphic(this.rank._id, file)
|
|
||||||
.subscribe((res) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.imagePreview = 'resource/rank/' + this.rank._id + '.png?' + Date.now();
|
|
||||||
}, 300);
|
|
||||||
fileInput.value = '';
|
|
||||||
this.showSuccessLabel = true;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.showSuccessLabel = false;
|
|
||||||
}, 2000)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {Routes} from "@angular/router";
|
import {Routes} from "@angular/router";
|
||||||
import {RankComponent} from "./ranks.component";
|
import {RankComponent} from "./ranks.component";
|
||||||
import {RankListComponent} from "./rank-list/rank-list.component";
|
import {RankListComponent} from "./rank-list/rank-list.component";
|
||||||
import {RankOverviewComponent} from "./rank-overview/rank-overview.component";
|
import {CreateRankComponent} from "./rank-new/new-rank.component";
|
||||||
|
|
||||||
|
|
||||||
export const ranksRoutes: Routes = [{
|
export const ranksRoutes: Routes = [{
|
||||||
|
@ -14,10 +14,15 @@ export const ranksRoutes: Routes = [{
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'overview/:id',
|
path: 'new',
|
||||||
component: RankOverviewComponent,
|
component: CreateRankComponent,
|
||||||
|
outlet: 'right'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'new/:id',
|
||||||
|
component: CreateRankComponent,
|
||||||
outlet: 'right'
|
outlet: 'right'
|
||||||
}];
|
}];
|
||||||
|
|
||||||
export const ranksRoutingComponents = [RankComponent, RankListComponent, RankOverviewComponent];
|
export const ranksRoutingComponents = [RankComponent, RankListComponent, CreateRankComponent];
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {Decoration, Rank} from "../../models/model-interfaces";
|
||||||
import {RequestMethod, RequestOptions, URLSearchParams} from "@angular/http";
|
import {RequestMethod, RequestOptions, URLSearchParams} from "@angular/http";
|
||||||
import {Observable} from "rxjs/Observable";
|
import {Observable} from "rxjs/Observable";
|
||||||
import {LOAD} from "../stores/decoration.store";
|
import {LOAD} from "../stores/decoration.store";
|
||||||
import {EDIT, RankStore, REMOVE} from "../stores/rank.store";
|
import {ADD, EDIT, RankStore, REMOVE} from "../stores/rank.store";
|
||||||
import {AppConfig} from "../../app.config";
|
import {AppConfig} from "../../app.config";
|
||||||
import {HttpClient} from "../http-client";
|
import {HttpClient} from "../http-client";
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ export class RankService {
|
||||||
|
|
||||||
this.http.get(this.config.apiUrl + this.config.apiRankPath, searchParams)
|
this.http.get(this.config.apiUrl + this.config.apiRankPath, searchParams)
|
||||||
.map(res => res.json())
|
.map(res => res.json())
|
||||||
.do((squads) => {
|
.do((ranks) => {
|
||||||
this.rankStore.dispatch({type: LOAD, data: squads});
|
this.rankStore.dispatch({type: LOAD, data: ranks});
|
||||||
}).subscribe(_ => {
|
}).subscribe(_ => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -42,6 +42,54 @@ export class RankService {
|
||||||
.map(res => res.json());
|
.map(res => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For creating new data with POST or
|
||||||
|
* update existing with patch PATCH
|
||||||
|
*/
|
||||||
|
submitRank(rank: Rank, imageFile?) {
|
||||||
|
let requestUrl = this.config.apiUrl + this.config.apiRankPath;
|
||||||
|
let requestMethod: RequestMethod;
|
||||||
|
let accessType;
|
||||||
|
let body;
|
||||||
|
|
||||||
|
if (rank._id) {
|
||||||
|
requestUrl += rank._id;
|
||||||
|
requestMethod = RequestMethod.Patch;
|
||||||
|
accessType = EDIT;
|
||||||
|
} else {
|
||||||
|
requestMethod = RequestMethod.Post;
|
||||||
|
accessType = ADD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageFile) {
|
||||||
|
body = new FormData();
|
||||||
|
Object.keys(rank).map((objectKey) => {
|
||||||
|
if (rank[objectKey] !== undefined) {
|
||||||
|
body.append(objectKey, rank[objectKey]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
body.append('image', imageFile, imageFile.name);
|
||||||
|
} else {
|
||||||
|
body = rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = new RequestOptions({
|
||||||
|
body: body,
|
||||||
|
method: requestMethod
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.http.request(requestUrl, options)
|
||||||
|
.map(res => res.json())
|
||||||
|
.do(savedRank => {
|
||||||
|
const action = {type: accessType, data: savedRank};
|
||||||
|
// leave some time to save image file before accessing it through listview
|
||||||
|
setTimeout(() => {
|
||||||
|
this.rankStore.dispatch(action);
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* send PATCH request to update db entry
|
* send PATCH request to update db entry
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
.form-control {
|
||||||
|
height: auto;
|
||||||
|
}
|
Loading…
Reference in New Issue