Тестовое задание на Angular. Создание страницы бронирования.
В данной статье создадим страницу для отображения вариантов для бронирования.
Создание BookingPage
После того как были созданы BookingState
и BookingService
создадим страницу на которой выведем варианты для бронирования.
ng g c booking-page
На странице с компонентом будем выводить два компонента: BookingMapComponent
и BookingListComponent
.
BookingMapComponent
— компонент, в котором выводится карта и отображаются доступные варианты для бронирования в виде маркеров на карте.BookingListComponent
— компонент, который просто выводит список доступных вариантов в виде списка.
Создадим каждый из вариантов:
ng g c booking-map
ng g c booking-list
Отличие мобильной версии от десктопной версии заключается в том, что в мобильной версии отображается либо карта, либо список, где по умолчанию отображается карта, а для того чтобы переключится на список, внизу будет плавающая кнопка, при клике по которой будет происходить смена экрана.
Добавим BookingPage
:
Как видно из реализации, мы добавляем контейнер, и в зависимости от расширения экрана показываем либо мобильную версию, либо версию для настольного компьютера:
<app-container mode="fluid" height="max-height">
<ng-container *ngIf="isDesktopScreen; then desktopTpl; else mobileTpl"></ng-container>
</app-container>
Переменная isDesktopScreen
определяется с помощью Angular CDK
:
this.breakpointObserver
.observe(mediaBreakpointUp(GridBreakpointType.Md))
.pipe(
tap((breakpoints) => {
this.isDesktopScreen = breakpoints.matches;
this.changeDetectorRef.markForCheck();
}),
takeUntil(this.destroy$)
)
.subscribe();
BreakpointObserver
позволяет отслеживать изменения размера экрана. В данном случае мы передаем на отслеживание правило — min-width: 768px
, которое формируется с помощью утилиты mediaBreakpointUp()
.
И если ширина экрана более 768px
, то тогда отображаем версию для настольного компьютера:
<ng-template #desktopTpl>
<app-row>
<app-column>
<app-booking-list automation-id="booking-list-desktop"></app-booking-list>
</app-column>
<app-column>
<app-booking-map automation-id="booking-map-desktop"><app-booking-card></app-booking-card></app-booking-map>
</app-column>
</app-row>
</ng-template>
В данном случае, здесь выводиться 2 компонента:
BookingListComponent
— компонент, который выводит список доступных вариантов для бронирования в виде спискаBookingMapComponent
— компонент, который выводит на карте список доступных вариантов для бронирования в виде маркеров, при клике на который можно открыть страницу с подробным описанием варианта.RowComponent
иColumnComponent
— создают колонки, аналогично сеткеbootstrap
.
В мобильной версии будет выведен макет:
<ng-template #mobileTpl>
<ng-container *ngIf="isMapShow; then mapMobileTpl; else listMobileTpl"></ng-container>
<div class="booking-actions">
<button class="booking-action" automation-id="booking-view-toggle" mat-icon-button type="button" (click)="onToggleView()">
<mat-icon *ngIf="isMapShow">view_list</mat-icon>
<mat-icon *ngIf="!isMapShow">map</mat-icon>
</button>
</div>
</ng-template><ng-template #mapMobileTpl>
<app-booking-map automation-id="booking-map-mobile"><app-booking-box></app-booking-box></app-booking-map>
</ng-template>
<ng-template #listMobileTpl>
<app-booking-list automation-id="booking-list-mobile"></app-booking-list>
</ng-template>
В зависимости от выбранного варианта (isMapShow
) отображения доступных вариантов для бронирования, выводится либо список либо карта.
Переключение вариантов происходит с помощью клика по кнопке:
<button class="booking-action" automation-id="booking-view-toggle" mat-icon-button type="button" (click)="onToggleView()">
<mat-icon *ngIf="isMapShow">view_list</mat-icon>
<mat-icon *ngIf="!isMapShow">map</mat-icon>
</button>
где в компоненте просто меняется значение на противоположное:
onToggleView(): void {
this.isMapShow = !this.isMapShow;
}
Создание BookingMap
Добавим реализацию компонента, который будет выводить карту с доступными вариантами.
Как видно из реализации, в BookingMap
используется ранее созданный компонент карты (Добавление google maps
).
<ng-container *ngIf="mapMarkers$ | async as mapMarkers">
<app-google-map
automation-id="booking-map-google"
[options]="options"
[markerOptions]="markerOptions"
[markers]="mapMarkers"
(mapMarkerClicked)="onMapMarkerClicked($event)"
(mapInfoWindowClosed)="onMapInfoWindowClosed()"
>
<ng-content></ng-content>
</app-google-map>
</ng-container>
В качестве параметров установим значения:
options: google.maps.MapOptions = {
center: {
lat: 59.93839227045331,
lng: 30.360033589998572,
},
zoom: 14,
};markerOptions: google.maps.MarkerOptions = { draggable: false, icon: '/' };
Значения маркеров получим из BookingService:
mapMarkers$!: Observable<MapMarkerConfig[]>;
constructor(private readonly bookingService: BookingService) {}
ngOnInit(): void {
this.mapMarkers$ = this.bookingService.mapMarkers$;
}
И соответственно при клике на пин или на карту происходят события открытия пина и закрытие ранее открытого варианта:
onMapMarkerClicked(markerConfig: MapMarkerConfig<BookingVariant>): void {
this.bookingService.setBookingVariant(markerConfig.data);
}
onMapInfoWindowClosed(): void {
this.bookingService.clearBookingVariant();
}
Стоит отметить, что в мобильной и десктопной версии имеются разные превью для доступных вариантов. В мобильной версии используется BookingBox, а в десктопной версии BookingCard
.
BookingBox:
BookingCard:
BookingCard
и BookingBox
выводят короткую информацию о доступном варианте. И соответственно при клике произойдет переход на страницу данного варианта.
Создание BookingList
Для вывода списка доступных вариантов создадим компонент:
Как видно из реализации, в компоненте получаем список доступных вариантов для бронирования:
bookingVariants$!: Observable<BookingVariant[]>;
constructor(private readonly bookingService: BookingService) {}
ngOnInit(): void {
this.bookingVariants$ = this.bookingService.bookingVariants$;
}
и затем их выводим, где для вывода используется BookingPortlet
:
<ng-container *ngIf="bookingVariants.length">
<app-booking-portlet
automation-id="booking-list-portlet"
[bookingVariant]="bookingVariant"
*ngFor="let bookingVariant of bookingVariants"
></app-booking-portlet>
</ng-container>
BookingPortlet
принимает вид:
В карточке доступного варианта выводим изображения первого номера, а также его цену и адрес.
Ссылки
Вернуться к оглавлению — Введение.
Следующая статья — Создание страницы апартаментов.
Предыдущая статья — Создание UI kit для приложения.
Все исходники на github/fafnur/barinb.
Группа в Medium: https://medium.com/fafnur
Группа в Vkontakte: https://vk.com/fafnur
Группа в Facebook: https://www.facebook.com/groups/fafnur/
Telegram канал: https://t.me/f_a_f_n_u_r
Twitter: https://twitter.com/Fafnur1
LinkedIn: https://www.linkedin.com/in/fafnur