This commit is contained in:
Phan Huy Tran 2024-11-20 11:22:11 +01:00
parent 3c6515f91f
commit 727a636b97
14 changed files with 138 additions and 16 deletions

View File

@ -1,6 +1,7 @@
import { Component } from '@angular/core'; import {Component, inject} from '@angular/core';
import { RouterOutlet } from '@angular/router'; import { RouterOutlet } from '@angular/router';
import {MainViewComponent} from './components/main-view/main-view.component'; import {MainViewComponent} from './components/main-view/main-view.component';
import {ShowService} from './services/show.service';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -11,4 +12,5 @@ import {MainViewComponent} from './components/main-view/main-view.component';
}) })
export class AppComponent { export class AppComponent {
title = 'netflix'; title = 'netflix';
showService: ShowService = inject(ShowService);
} }

View File

@ -2,7 +2,8 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router'; import { provideRouter } from '@angular/router';
import { routes } from './app.routes'; import { routes } from './app.routes';
import {provideHttpClient} from '@angular/common/http';
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideHttpClient()]
}; };

View File

@ -2,9 +2,12 @@
<div class="row mt-3"><h1>TV-Serien</h1></div> <div class="row mt-3"><h1>TV-Serien</h1></div>
<div class="row mt-1"> <div class="row mt-1">
<div class="col-md-7 mb-3"> <div class="col-md-7 mb-3">
<app-show-list></app-show-list> <app-show-list [shows]="shows" (selectedShow)="onSelectedShow($event)"></app-show-list>
</div> </div>
<div class="col-md-5"> <div class="col-md-5">
@if (isShowSelected) {
<app-show-details [detailShow$]="selectedShow$"></app-show-details>
}
</div> </div>
<app-show-form></app-show-form> <app-show-form></app-show-form>
</div> </div>

View File

@ -1,16 +1,41 @@
import {Component} from '@angular/core'; import {Component, inject} from '@angular/core';
import {ShowListComponent} from '../show-list/show-list.component'; import {ShowListComponent} from '../show-list/show-list.component';
import {Show} from '../../model/show';
import {ShowService} from '../../services/show.service';
import {ShowFormComponent} from '../show-form/show-form.component'; import {ShowFormComponent} from '../show-form/show-form.component';
import {BehaviorSubject} from 'rxjs';
import {ApiService} from '../../services/api-service';
import {ShowDetailsComponent} from '../show-details/show-details.component';
@Component({ @Component({
selector: 'app-main-view', selector: 'app-main-view',
standalone: true, standalone: true,
imports: [ imports: [
ShowListComponent, ShowListComponent,
ShowFormComponent ShowFormComponent,
ShowDetailsComponent
], ],
templateUrl: './main-view.component.html', templateUrl: './main-view.component.html',
styleUrl: './main-view.component.css' styleUrl: './main-view.component.css'
}) })
export class MainViewComponent { export class MainViewComponent {
private dataService: ShowService = inject(ShowService);
private apiService: ApiService = inject(ApiService);
public shows: Show[] = [];
selectedShow$: BehaviorSubject<Show>;
isShowSelected = false;
constructor() {
this.shows = this.dataService.getShows();
this.selectedShow$ = new BehaviorSubject<Show>(new Show(0, ""))
}
onSelectedShow(show: Show) {
const title = show.title ?? '';
this.apiService.getDetailShow(title).subscribe((s) => {
this.selectedShow$.next(s);
});
this.isShowSelected = true;
}
} }

View File

@ -0,0 +1,9 @@
@if (detailShow$ | async; as detailShow) {
<div class="card">
<img class="card-img-top img-fluid" ngSrc="{{detailShow.image}}">
<div class="card-body">
<h4 class="card-title">{{ detailShow.title }}</h4>
<p class="card-text" [innerHTML]="detailShow.summary"></p></div>
</div>
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ShowDetailsComponent } from './show-details.component';
describe('ShowDetailsComponent', () => {
let component: ShowDetailsComponent;
let fixture: ComponentFixture<ShowDetailsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ShowDetailsComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ShowDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,18 @@
import {Component, Input} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
import {Show} from '../../model/show';
import {AsyncPipe, NgOptimizedImage} from '@angular/common';
@Component({
selector: 'app-show-details',
standalone: true,
imports: [
AsyncPipe,
NgOptimizedImage
],
templateUrl: './show-details.component.html',
styleUrl: './show-details.component.css'
})
export class ShowDetailsComponent {
@Input() detailShow$?: BehaviorSubject<Show>;
}

View File

@ -14,12 +14,12 @@ import {FormsModule} from '@angular/forms';
}) })
export class ShowFormComponent { export class ShowFormComponent {
showService: ShowService = inject(ShowService); showService: ShowService = inject(ShowService);
show: Show = new Show(null, null); show: Show = new Show(0, "");
shows: Show[] = this.showService.getShows(); shows: Show[] = this.showService.getShows();
save() { save() {
this.shows.push(this.show); this.shows.push(this.show);
this.show = new Show(null, null); this.show = new Show(0, "");
} }
} }

View File

@ -17,6 +17,9 @@
<tr> <tr>
<td>{{ show.id }}</td> <td>{{ show.id }}</td>
<td>{{ show.title }}</td> <td>{{ show.title }}</td>
<td>
<button class="btn btn-primary" (click)="showDetails(show)">Details</button>
</td>
<td> <td>
<button class="btn btn-secondary" (click)="edit(show)">Bearbeiten</button> <button class="btn btn-secondary" (click)="edit(show)">Bearbeiten</button>
</td> </td>

View File

@ -1,6 +1,5 @@
import {Component, inject} from '@angular/core'; import {Component, EventEmitter, Input, Output} from '@angular/core';
import {Show} from '../../model/show'; import {Show} from '../../model/show';
import {ShowService} from '../../services/show.service';
import {FormsModule} from '@angular/forms'; import {FormsModule} from '@angular/forms';
@Component({ @Component({
@ -13,9 +12,13 @@ import {FormsModule} from '@angular/forms';
styleUrl: './show-list.component.css' styleUrl: './show-list.component.css'
}) })
export class ShowListComponent { export class ShowListComponent {
showService: ShowService = inject(ShowService); @Input() shows: Show[] = [];
shows: Show[] = this.showService.getShows(); @Output() selectedShow = new EventEmitter<Show>();
editShow: Show = new Show(null, null); editShow: Show = new Show(0, "");
showDetails(show: Show) {
this.selectedShow.emit(show);
}
edit(show: Show) { edit(show: Show) {
this.editShow = show; this.editShow = show;
@ -24,7 +27,7 @@ export class ShowListComponent {
saveEdit() { saveEdit() {
this.updateShow(this.editShow); this.updateShow(this.editShow);
this.editShow = new Show(null, null); this.editShow = new Show(0, "");
} }
updateShow(show: Show) { updateShow(show: Show) {

11
src/app/model/ShowDto.ts Normal file
View File

@ -0,0 +1,11 @@
export class ShowDTO {
constructor(
public id: number,
public title: string,
public image?: {
medium: string;
original: string;
},
public summary?: string) {
}
}

View File

@ -1,4 +1,4 @@
export class Show { export class Show {
constructor(public id: number|null, public title: string|null) { constructor(public id?: number, public title?: string, public image?: string, public summary?: string) {
} }
} }

View File

@ -0,0 +1,24 @@
import {inject, Injectable} from '@angular/core';
import {Show} from '../model/show';
import {HttpClient} from '@angular/common/http';
import {map, Observable} from 'rxjs';
import {ShowDTO} from '../model/ShowDto';
@Injectable({
providedIn: 'root'
})
export class ApiService {
private baseUrl: string = "https://api.tvmaze.com";
httpClient: HttpClient = inject(HttpClient);
getDetailShow(title: string): Observable<Show> {
const apiUrl = `${this.baseUrl}/singlesearch/shows?q=${title}`;
let show: Show = new Show(0, title);
return this.httpClient.get<ShowDTO>(apiUrl).pipe(map((s) => {
show.summary = s.summary;
show.image = s.image?.medium;
return show;
}));
}
}