feat: add hotel details and list components with routing
This commit is contained in:
parent
d773cfe4bf
commit
8dd8b8b438
@ -7,4 +7,5 @@
|
|||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
<img src="{{hotel.imageUrl}}" alt="Hotel">
|
<img src="{{hotel.imageUrl}}" alt="Hotel">
|
||||||
|
<a *ngIf="!isDetail" routerLink="/hotels/{{hotel.id}}">Details</a>
|
||||||
<app-star-rating [rating]="hotel.rating"></app-star-rating>
|
<app-star-rating [rating]="hotel.rating"></app-star-rating>
|
||||||
|
@ -5,18 +5,21 @@ import { CurrencyPipe, NgIf } from "@angular/common";
|
|||||||
import { FormsModule } from "@angular/forms";
|
import { FormsModule } from "@angular/forms";
|
||||||
import { StarRatingComponent } from "../star-rating/star-rating.component";
|
import { StarRatingComponent } from "../star-rating/star-rating.component";
|
||||||
import { HttpClient } from "@angular/common/http";
|
import { HttpClient } from "@angular/common/http";
|
||||||
|
import { RouterLink } from "@angular/router";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hotel-item',
|
selector: 'app-hotel-item',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
templateUrl: './HotelItem.component.html',
|
templateUrl: './HotelItem.component.html',
|
||||||
imports: [ChildComponent, CurrencyPipe, FormsModule, StarRatingComponent, NgIf],
|
imports: [ChildComponent, CurrencyPipe, FormsModule, StarRatingComponent, NgIf, RouterLink],
|
||||||
})
|
})
|
||||||
export class HotelItem {
|
export class HotelItem {
|
||||||
|
|
||||||
@Input() public hotel!: Hotel;
|
@Input() public hotel!: Hotel;
|
||||||
public selectedLanguage?: string;
|
public selectedLanguage?: string;
|
||||||
|
|
||||||
|
@Input() public isDetail: boolean = false;
|
||||||
|
|
||||||
public languageChange(lang: string) {
|
public languageChange(lang: string) {
|
||||||
this.selectedLanguage = lang;
|
this.selectedLanguage = lang;
|
||||||
console.log(this.selectedLanguage);
|
console.log(this.selectedLanguage);
|
||||||
|
@ -51,7 +51,6 @@ export class HotelData implements InMemoryDbService {
|
|||||||
return { hotels };
|
return { hotels };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
genId(hotels: Hotel[]): number {
|
genId(hotels: Hotel[]): number {
|
||||||
return hotels.length > 0 ? Math.max(...hotels.map(hotel => hotel.id)) + 1 : 1;
|
return hotels.length > 0 ? Math.max(...hotels.map(hotel => hotel.id)) + 1 : 1;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
<h1>{{'hello' | uppercase | text}}</h1>
|
<router-outlet></router-outlet>
|
||||||
<app-search [(input)]="search"></app-search>
|
|
||||||
@if (hotels[0].hotelName) {
|
|
||||||
<div *ngFor="let hotel of hotels">
|
|
||||||
<app-hotel-item *ngIf="hotel.hotelName.includes(search)" [hotel]="hotel"></app-hotel-item>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<!-- <p>ID: {{response.id}}</p> -->
|
<!-- <p>ID: {{response.id}}</p> -->
|
||||||
<!-- <p>userId: {{response.userId}}</p> -->
|
<!-- <p>userId: {{response.userId}}</p> -->
|
||||||
<!-- <p>title: {{response.title}}</p> -->
|
<!-- <p>title: {{response.title}}</p> -->
|
||||||
|
@ -8,70 +8,17 @@ import { inject } from '@angular/core';
|
|||||||
import { filter, from, last, map, Observable, scan } from 'rxjs';
|
import { filter, from, last, map, Observable, scan } from 'rxjs';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Hotel } from './HotelItem/hotel';
|
import { Hotel } from './HotelItem/hotel';
|
||||||
|
import { RouterOutlet } from '@angular/router';
|
||||||
interface User {
|
|
||||||
name: string;
|
|
||||||
age: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable({providedIn: "root"})
|
@Injectable({providedIn: "root"})
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [NgFor, NgForOf, NgIf, HotelItem, SearchComponent, UpperCasePipe, TextPipe, AsyncPipe],
|
imports: [RouterOutlet, NgFor, NgForOf, NgIf, HotelItem, SearchComponent, UpperCasePipe, TextPipe, AsyncPipe],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
providers: [HotelService],
|
providers: [HotelService],
|
||||||
styleUrl: './app.component.css'
|
styleUrl: './app.component.css'
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
public search: string = "";
|
|
||||||
public hotelService: HotelService = inject(HotelService);
|
|
||||||
public response: any = null;
|
|
||||||
public hotels: Array<Hotel> = [{} as Hotel];
|
|
||||||
|
|
||||||
constructor (private http: HttpClient) {
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.http.get<Array<Hotel>>("api/hotels").subscribe(res => {
|
|
||||||
this.hotels = res;
|
|
||||||
});
|
|
||||||
|
|
||||||
const users = [
|
|
||||||
{ name: "Max", age: 21 },
|
|
||||||
{ name: "Peter", age: 31 },
|
|
||||||
{ name: "Hans", age: 13 },
|
|
||||||
{ name: "Klaus", age: 51 },
|
|
||||||
{ name: "Dieter", age: 1 },
|
|
||||||
{ name: "Jan-Marlon", age: 3 },
|
|
||||||
]
|
|
||||||
|
|
||||||
const stream: Observable<User> = from(users);
|
|
||||||
|
|
||||||
stream.pipe(
|
|
||||||
filter((user) => user.age > 18),
|
|
||||||
scan((acc, user) => acc + user.age, 0),
|
|
||||||
map((ageSum, index) => ageSum / (index + 1)),
|
|
||||||
last(),
|
|
||||||
).subscribe(console.log);
|
|
||||||
|
|
||||||
// const stream: Observable<number | string> = from([5, 1, 2, 12, 5, 14, 17, 5, "testing"]);
|
|
||||||
|
|
||||||
// stream.pipe(
|
|
||||||
// filter((value) => typeof value === "number"),
|
|
||||||
// tap((value) => console.log("Zahl:" + value)),
|
|
||||||
// filter((value: number) => value % 2 === 0),
|
|
||||||
// tap((value) => console.log("Gerade Zahl: " + value)),
|
|
||||||
// toArray(),
|
|
||||||
//).subscribe(console.log);
|
|
||||||
}
|
|
||||||
|
|
||||||
public test() {
|
|
||||||
console.log(this.search);
|
|
||||||
}
|
|
||||||
|
|
||||||
// public foundHotels = this.hotels.pipe(
|
|
||||||
// filter((hotel) => hotel.hotelName.includes(this.search)),
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,5 +12,9 @@ import { HotelData } from './api/api';
|
|||||||
registerLocaleData(localeDe, 'de-DE');
|
registerLocaleData(localeDe, 'de-DE');
|
||||||
registerLocaleData(localeCn, 'cn-CN');
|
registerLocaleData(localeCn, 'cn-CN');
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideHttpClient(), importProvidersFrom(InMemoryWebApiModule.forRoot(HotelData))]
|
providers: [
|
||||||
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||||
|
provideRouter(routes),
|
||||||
|
provideHttpClient(),
|
||||||
|
importProvidersFrom(InMemoryWebApiModule.forRoot(HotelData))]
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,14 @@
|
|||||||
import { Routes } from '@angular/router';
|
import { Routes } from '@angular/router';
|
||||||
|
import { HotelDetailsComponent } from './hotel-details/hotel-details.component';
|
||||||
|
import { HotelListComponent } from './hotel-list/hotel-list.component';
|
||||||
|
|
||||||
export const routes: Routes = [];
|
export const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: "",
|
||||||
|
component: HotelListComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "hotels/:id",
|
||||||
|
component: HotelDetailsComponent,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
0
src/app/hotel-details/hotel-details.component.css
Normal file
0
src/app/hotel-details/hotel-details.component.css
Normal file
1
src/app/hotel-details/hotel-details.component.html
Normal file
1
src/app/hotel-details/hotel-details.component.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<app-hotel-item [hotel]="hotel" [isDetail]="true"></app-hotel-item>
|
23
src/app/hotel-details/hotel-details.component.spec.ts
Normal file
23
src/app/hotel-details/hotel-details.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HotelDetailsComponent } from './hotel-details.component';
|
||||||
|
|
||||||
|
describe('HotelDetailsComponent', () => {
|
||||||
|
let component: HotelDetailsComponent;
|
||||||
|
let fixture: ComponentFixture<HotelDetailsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [HotelDetailsComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(HotelDetailsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
29
src/app/hotel-details/hotel-details.component.ts
Normal file
29
src/app/hotel-details/hotel-details.component.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { Hotel } from '../HotelItem/hotel';
|
||||||
|
import { CurrencyPipe } from '@angular/common';
|
||||||
|
import { StarRatingComponent } from '../star-rating/star-rating.component';
|
||||||
|
import { HotelItem } from '../HotelItem/HotelItem.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-hotel-details',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CurrencyPipe, StarRatingComponent, HotelItem],
|
||||||
|
templateUrl: './hotel-details.component.html',
|
||||||
|
styleUrl: './hotel-details.component.css'
|
||||||
|
})
|
||||||
|
export class HotelDetailsComponent implements OnInit {
|
||||||
|
public hotel: any;
|
||||||
|
|
||||||
|
constructor(private route: ActivatedRoute, private http: HttpClient) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const routeParams = this.route.snapshot.paramMap;
|
||||||
|
const hotelId = routeParams.get("id");
|
||||||
|
|
||||||
|
this.http.get<Hotel>("api/hotels/" + hotelId).subscribe(res => {
|
||||||
|
this.hotel = res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
0
src/app/hotel-list/hotel-list.component.css
Normal file
0
src/app/hotel-list/hotel-list.component.css
Normal file
7
src/app/hotel-list/hotel-list.component.html
Normal file
7
src/app/hotel-list/hotel-list.component.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<h1>{{'hello' | uppercase | text}}</h1>
|
||||||
|
<app-search [(input)]="search"></app-search>
|
||||||
|
@if (hotels[0].hotelName) {
|
||||||
|
<div *ngFor="let hotel of hotels">
|
||||||
|
<app-hotel-item *ngIf="hotel.hotelName.includes(search)" [hotel]="hotel"></app-hotel-item>
|
||||||
|
</div>
|
||||||
|
}
|
23
src/app/hotel-list/hotel-list.component.spec.ts
Normal file
23
src/app/hotel-list/hotel-list.component.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HotelListComponent } from './hotel-list.component';
|
||||||
|
|
||||||
|
describe('HotelListComponent', () => {
|
||||||
|
let component: HotelListComponent;
|
||||||
|
let fixture: ComponentFixture<HotelListComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [HotelListComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(HotelListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
73
src/app/hotel-list/hotel-list.component.ts
Normal file
73
src/app/hotel-list/hotel-list.component.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { CommonModule, NgFor, NgIf, UpperCasePipe } from '@angular/common';
|
||||||
|
import { Component, inject } from '@angular/core';
|
||||||
|
import { TextPipe } from '../../text.pipe';
|
||||||
|
import { SearchComponent } from '../Search/search.component';
|
||||||
|
import { HotelService } from '../Parent/services/hotel.service';
|
||||||
|
import { Hotel } from '../HotelItem/hotel';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { filter, from, last, map, Observable, scan } from 'rxjs';
|
||||||
|
import { HotelItem } from '../HotelItem/HotelItem.component';
|
||||||
|
|
||||||
|
interface User {
|
||||||
|
name: string;
|
||||||
|
age: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-hotel-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [UpperCasePipe, TextPipe, SearchComponent, HotelItem, NgFor, NgIf],
|
||||||
|
templateUrl: './hotel-list.component.html',
|
||||||
|
styleUrl: './hotel-list.component.css'
|
||||||
|
})
|
||||||
|
export class HotelListComponent {
|
||||||
|
public search: string = "";
|
||||||
|
public hotelService: HotelService = inject(HotelService);
|
||||||
|
public response: any = null;
|
||||||
|
public hotels: Array<Hotel> = [{} as Hotel];
|
||||||
|
|
||||||
|
constructor (private http: HttpClient) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.http.get<Array<Hotel>>("api/hotels").subscribe(res => {
|
||||||
|
this.hotels = res;
|
||||||
|
});
|
||||||
|
|
||||||
|
const users = [
|
||||||
|
{ name: "Max", age: 21 },
|
||||||
|
{ name: "Peter", age: 31 },
|
||||||
|
{ name: "Hans", age: 13 },
|
||||||
|
{ name: "Klaus", age: 51 },
|
||||||
|
{ name: "Dieter", age: 1 },
|
||||||
|
{ name: "Jan-Marlon", age: 3 },
|
||||||
|
]
|
||||||
|
|
||||||
|
const stream: Observable<User> = from(users);
|
||||||
|
|
||||||
|
stream.pipe(
|
||||||
|
filter((user) => user.age > 18),
|
||||||
|
scan((acc, user) => acc + user.age, 0),
|
||||||
|
map((ageSum, index) => ageSum / (index + 1)),
|
||||||
|
last(),
|
||||||
|
).subscribe(console.log);
|
||||||
|
|
||||||
|
// const stream: Observable<number | string> = from([5, 1, 2, 12, 5, 14, 17, 5, "testing"]);
|
||||||
|
|
||||||
|
// stream.pipe(
|
||||||
|
// filter((value) => typeof value === "number"),
|
||||||
|
// tap((value) => console.log("Zahl:" + value)),
|
||||||
|
// filter((value: number) => value % 2 === 0),
|
||||||
|
// tap((value) => console.log("Gerade Zahl: " + value)),
|
||||||
|
// toArray(),
|
||||||
|
//).subscribe(console.log);
|
||||||
|
}
|
||||||
|
|
||||||
|
public test() {
|
||||||
|
console.log(this.search);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public foundHotels = this.hotels.pipe(
|
||||||
|
// filter((hotel) => hotel.hotelName.includes(this.search)),
|
||||||
|
// );
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user