edit song
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<mat-card-title>Titel bearbeiten</mat-card-title>
|
<mat-card-title>Titel bearbeiten</mat-card-title>
|
||||||
<!-- <mat-card-subtitle>{{ song.Key }} - {{ song.Tempo }}</mat-card-subtitle> -->
|
<mat-card-subtitle>Daten werden nach der Eingabe automatisch gespeichert</mat-card-subtitle>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<form>
|
<form>
|
||||||
@@ -47,6 +47,14 @@
|
|||||||
[matTextareaAutosize]="true"
|
[matTextareaAutosize]="true"
|
||||||
></textarea>
|
></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
<mat-form-field>
|
||||||
|
<textarea
|
||||||
|
matInput
|
||||||
|
placeholder="Kommentare"
|
||||||
|
[formControl]="form.controls.Comments"
|
||||||
|
[matTextareaAutosize]="true"
|
||||||
|
></textarea>
|
||||||
|
</mat-form-field>
|
||||||
</form>
|
</form>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<!-- <mat-card-actions>
|
<!-- <mat-card-actions>
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<p *ngFor="let line of text">{{ line }}</p>
|
<p *ngFor="let line of text">{{ line }}</p>
|
||||||
|
<br />
|
||||||
|
<p *ngFor="let line of comments">{{ line }}</p>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions>
|
<mat-card-actions>
|
||||||
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
<button mat-button (click)="onClickDownload()">Herunterladen</button>
|
||||||
|
|||||||
@@ -1,22 +1,4 @@
|
|||||||
.mat-card {
|
p {
|
||||||
width: 500px;
|
margin: 0;
|
||||||
border-radius: 8px;
|
min-height: 10px;
|
||||||
background: #fffe;
|
|
||||||
margin: 20px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-card-title {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
width: 420px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mat-card-content {
|
|
||||||
white-space: pre-wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.song-detail-container {
|
|
||||||
margin-left: 30vw;
|
|
||||||
}
|
}
|
||||||
@@ -52,6 +52,10 @@ export class SongComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get text(): string[] {
|
public get text(): string[] {
|
||||||
return this.song.Text.split(/\r?\n/).filter(_ => _ !== ' ');
|
return this.song.Text ? this.song.Text.split(/\r?\n/) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public get comments(): string[] {
|
||||||
|
return this.song.Comments ? this.song.Comments.split(/\r?\n/) : [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,40 @@
|
|||||||
import { Song } from 'src/app/models/song.model';
|
|
||||||
import { SongsService } from 'src/app/data/songs.service';
|
import { SongsService } from 'src/app/data/songs.service';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||||
|
import { switchMap, tap } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class EditSongService {
|
export class EditSongService {
|
||||||
|
constructor(private songsService: SongsService) {}
|
||||||
|
|
||||||
constructor(private songsService: SongsService) { }
|
public initEditForm(): FormGroup {
|
||||||
|
const song = this.songsService.selectedSong.value;
|
||||||
|
const form = new FormGroup({
|
||||||
|
ID: new FormControl(song.ID, { updateOn: 'blur' }),
|
||||||
|
Number: new FormControl(song.Number, { updateOn: 'blur' }),
|
||||||
|
Name: new FormControl(song.Name, {
|
||||||
|
updateOn: 'blur',
|
||||||
|
validators: Validators.required
|
||||||
|
}),
|
||||||
|
Text: new FormControl(song.Text, { updateOn: 'blur' }),
|
||||||
|
SongType: new FormControl(song.SongType, {
|
||||||
|
updateOn: 'blur',
|
||||||
|
validators: Validators.required
|
||||||
|
}),
|
||||||
|
Key: new FormControl(song.Key, { updateOn: 'blur' }),
|
||||||
|
Tempo: new FormControl(song.Tempo, { updateOn: 'blur' }),
|
||||||
|
Comments: new FormControl(song.Comments, { updateOn: 'blur' }),
|
||||||
|
});
|
||||||
|
|
||||||
public initEditForm(): FormGroup {
|
const controls = Object.keys(form.controls);
|
||||||
const song = this.songsService.selectedSong.value;
|
controls.forEach(control => {
|
||||||
const form = new FormGroup({
|
form.controls[control].valueChanges.pipe(
|
||||||
ID: new FormControl(song.ID),
|
switchMap(value => this.songsService.patch(song.ID, control, value))
|
||||||
Number: new FormControl(song.Number),
|
).subscribe();
|
||||||
Name: new FormControl(song.Name, Validators.required),
|
});
|
||||||
Text: new FormControl(song.Text),
|
|
||||||
SongType: new FormControl(song.SongType, Validators.required),
|
|
||||||
Key: new FormControl(song.Key),
|
|
||||||
Tempo: new FormControl(song.Tempo)
|
|
||||||
});
|
|
||||||
|
|
||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,45 @@
|
|||||||
import { ODataService, ODataQuery } from 'odata-v4-ng';
|
import { ODataService, ODataQuery } from "odata-v4-ng";
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from "rxjs";
|
||||||
import { map } from 'rxjs/operators';
|
import { map, tap } from "rxjs/operators";
|
||||||
import { base } from './urls';
|
import { base } from "./urls";
|
||||||
|
|
||||||
export class OdataService {
|
export class OdataService {
|
||||||
private url: string;
|
private url: string;
|
||||||
constructor(private odataService: ODataService, private entity: string) {
|
constructor(private odataService: ODataService, private entity: string) {
|
||||||
this.url = base + '/odata/';
|
this.url = base + "/odata/";
|
||||||
}
|
}
|
||||||
|
|
||||||
public list<TResponse>(): Observable<TResponse[]> {
|
public list<TResponse>(properties: string[]): Observable<TResponse[]> {
|
||||||
const query = new ODataQuery(this.odataService, this.url).entitySet(
|
const query = new ODataQuery(this.odataService, this.url)
|
||||||
this.entity
|
.entitySet(this.entity)
|
||||||
);
|
.select(properties);
|
||||||
const get = query.get().pipe(map(_ => _.toPropertyValue<TResponse[]>()));
|
const get = query.get().pipe(map(_ => _.toPropertyValue<TResponse[]>()));
|
||||||
|
|
||||||
return get;
|
return get;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get<TResponse>(id: number): Observable<TResponse> {
|
public get<TResponse>(
|
||||||
|
id: number,
|
||||||
|
properties: string[]
|
||||||
|
): Observable<TResponse> {
|
||||||
const query = new ODataQuery(this.odataService, this.url)
|
const query = new ODataQuery(this.odataService, this.url)
|
||||||
.entitySet(this.entity)
|
.entitySet(this.entity)
|
||||||
.entityKey(id);
|
.entityKey(id)
|
||||||
|
.select(properties);
|
||||||
const get = query.get().pipe(map(_ => _.toEntity<TResponse>()));
|
const get = query.get().pipe(map(_ => _.toEntity<TResponse>()));
|
||||||
|
|
||||||
return get;
|
return get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public patch(id: number, control: string, value: any): Observable<boolean> {
|
||||||
|
const valueSet = { [control]: value };
|
||||||
|
const query = new ODataQuery(this.odataService, this.url)
|
||||||
|
.entitySet(this.entity)
|
||||||
|
.entityKey(id);
|
||||||
|
const get = query.patch(valueSet).pipe(
|
||||||
|
map(() => true)
|
||||||
|
);
|
||||||
|
|
||||||
|
return get;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import { Injectable } from '@angular/core';
|
|||||||
import { ODataService } from 'odata-v4-ng';
|
import { ODataService } from 'odata-v4-ng';
|
||||||
import { OdataService } from './odata.service';
|
import { OdataService } from './odata.service';
|
||||||
import { Song } from '../models/song.model';
|
import { Song } from '../models/song.model';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { tap } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -18,17 +19,39 @@ export class SongsService extends OdataService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public loadSongList(): void {
|
public loadSongList(): void {
|
||||||
this.list<Song>().subscribe(_ => this.songs.next(_));
|
const properties = ['ID', 'Name', 'Number', 'SongType', 'Key', 'Tempo'];
|
||||||
|
this.list<Song>(properties).subscribe(_ => this.songs.next(_));
|
||||||
}
|
}
|
||||||
|
|
||||||
public selectSong(id: number): void {
|
public selectSong(id: number): void {
|
||||||
this.edit = false;
|
this.edit = false;
|
||||||
const filter = this.songs.value.filter(_ => _.ID === id);
|
const filter = this.songs.value.filter(_ => _.ID === id);
|
||||||
const song = filter.length === 1 ? filter[0] : null;
|
const song = filter.length === 1 ? filter[0] : null;
|
||||||
this.selectedSong.next(song);
|
if (!song) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.get<Song>(id, ['Text', 'Comments']).subscribe(_ => {
|
||||||
|
song.Text = _.Text;
|
||||||
|
song.Comments = _.Comments;
|
||||||
|
this.selectedSong.next(song);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetSelectedSong() {
|
public resetSelectedSong() {
|
||||||
this.selectedSong.next(null);
|
this.selectedSong.next(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public patch(id: number, control: string, value: any): Observable<boolean> {
|
||||||
|
const patch = super.patch(id, control, value).pipe(
|
||||||
|
tap(() => {
|
||||||
|
const songs = this.songs.value;
|
||||||
|
const song = songs.filter(_ => _.ID === id)[0];
|
||||||
|
song[control] = value;
|
||||||
|
this.songs.next(songs);
|
||||||
|
this.selectedSong.next(song);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return patch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export const base = 'http://test.benjamin-ifland.de/';
|
// export const base = 'http://192.168.178.20/API';
|
||||||
|
export const base = 'http://test.benjamin-ifland.de';
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { trigger, transition, style, animate } from '@angular/animations';
|
|||||||
export const blend = trigger('blend', [
|
export const blend = trigger('blend', [
|
||||||
transition(':enter', [
|
transition(':enter', [
|
||||||
style({ opacity: 0 }),
|
style({ opacity: 0 }),
|
||||||
animate('700ms', style({ opacity: 0 })),
|
animate('200ms', style({ opacity: 0 })),
|
||||||
animate('300ms', style({ opacity: 1 }))
|
animate('300ms', style({ opacity: 1 }))
|
||||||
]),
|
]),
|
||||||
transition(':leave', [
|
transition(':leave', [
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mat-card {
|
.mat-card {
|
||||||
width: 500px;
|
width: 600px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: #fffd;
|
background: #fffd;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
@@ -84,7 +84,7 @@ html {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
width: 420px;
|
width: 520px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mat-card-content {
|
.mat-card-content {
|
||||||
|
|||||||
Reference in New Issue
Block a user