Issue: #109
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
<div>
|
||||
<label for="type" class="block text-sm font-bold text-gray-700 mb-1 relative w-fit {{ labelClasses }}"
|
||||
>{{ label }} @if(validationMessage){
|
||||
<div
|
||||
attr.data-tooltip-target="tooltip-{{ name }}"
|
||||
class="absolute inline-flex items-center justify-center w-6 h-6 text-xs font-bold text-white bg-red-500 border-2 border-white rounded-full -top-2 dark:border-gray-900 hover:cursor-pointer"
|
||||
(click)="toggleTooltip($event)"
|
||||
(touchstart)="toggleTooltip($event)"
|
||||
>
|
||||
!
|
||||
</div>
|
||||
<app-tooltip id="tooltip-{{ name }}" [text]="validationMessage" [isVisible]="isTooltipVisible"></app-tooltip>
|
||||
}
|
||||
</label>
|
||||
<ng-select
|
||||
class="custom"
|
||||
[multiple]="false"
|
||||
[hideSelected]="true"
|
||||
[trackByFn]="trackByFn"
|
||||
[minTermLength]="2"
|
||||
[loading]="placeLoading"
|
||||
typeToSearchText="Please enter 2 or more characters"
|
||||
[typeahead]="placeInput$"
|
||||
ngModel="{{ formatGeoAddress(value) }}"
|
||||
(ngModelChange)="onInputChange($event)"
|
||||
>
|
||||
@for (place of places$ | async; track place.place_id) {
|
||||
<ng-option [value]="place">{{ formatPlaceAddress(place) }}</ng-option>
|
||||
}
|
||||
</ng-select>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
:host ::ng-deep .ng-select.custom .ng-select-container {
|
||||
// --tw-bg-opacity: 1;
|
||||
// background-color: rgb(249 250 251 / var(--tw-bg-opacity));
|
||||
// height: 42px;
|
||||
border-radius: 0.5rem;
|
||||
.ng-value-container .ng-input {
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, forwardRef, Input } from '@angular/core';
|
||||
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||
import { NgSelectModule } from '@ng-select/ng-select';
|
||||
import { catchError, concat, debounceTime, distinctUntilChanged, Observable, of, Subject, switchMap, tap } from 'rxjs';
|
||||
import { GeoResult } from '../../../../../bizmatch-server/src/models/main.model';
|
||||
import { Place } from '../../../../../bizmatch-server/src/models/server.model';
|
||||
import { GeoService } from '../../services/geo.service';
|
||||
import { SelectOptionsService } from '../../services/select-options.service';
|
||||
import { BaseInputComponent } from '../base-input/base-input.component';
|
||||
import { TooltipComponent } from '../tooltip/tooltip.component';
|
||||
import { ValidationMessagesService } from '../validation-messages.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-validated-location',
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule, NgSelectModule, TooltipComponent],
|
||||
templateUrl: './validated-location.component.html',
|
||||
styleUrl: './validated-location.component.scss',
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => ValidatedLocationComponent),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class ValidatedLocationComponent extends BaseInputComponent {
|
||||
@Input() items;
|
||||
@Input() labelClasses: string;
|
||||
places$: Observable<Place[]>;
|
||||
placeInput$ = new Subject<string>();
|
||||
placeLoading = false;
|
||||
constructor(validationMessagesService: ValidationMessagesService, private geoService: GeoService, public selectOptions: SelectOptionsService) {
|
||||
super(validationMessagesService);
|
||||
}
|
||||
|
||||
override ngOnInit() {
|
||||
super.ngOnInit();
|
||||
this.loadCities();
|
||||
}
|
||||
onInputChange(event: Place): void {
|
||||
this.value = event; //{ ...event, longitude: parseFloat(event.longitude), latitude: parseFloat(event.latitude) };
|
||||
this.value = {
|
||||
id: event?.place_id,
|
||||
name: event?.address.city,
|
||||
county: event?.address.county,
|
||||
street: event?.address.road,
|
||||
housenumber: event?.address.house_number,
|
||||
state: event?.address['ISO3166-2-lvl4'].substr(3),
|
||||
latitude: event ? parseFloat(event?.lat) : undefined,
|
||||
longitude: event ? parseFloat(event?.lon) : undefined,
|
||||
};
|
||||
this.onChange(this.value);
|
||||
}
|
||||
private loadCities() {
|
||||
this.places$ = concat(
|
||||
of([]), // default items
|
||||
this.placeInput$.pipe(
|
||||
debounceTime(300),
|
||||
distinctUntilChanged(),
|
||||
tap(() => (this.placeLoading = true)),
|
||||
switchMap(term =>
|
||||
this.geoService.findLocationStartingWith(term).pipe(
|
||||
catchError(() => of([])), // empty list on error
|
||||
// map(cities => cities.map(city => city.city)), // transform the list of objects to a list of city names
|
||||
tap(() => (this.placeLoading = false)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
trackByFn(item: GeoResult) {
|
||||
return item.id;
|
||||
}
|
||||
compareFn = (item, selected) => {
|
||||
return item.id === selected.id;
|
||||
};
|
||||
formatGeoAddress(geoResult: GeoResult | null | undefined): string {
|
||||
// Überprüfen, ob geoResult null oder undefined ist
|
||||
if (!geoResult) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let addressParts: string[] = [];
|
||||
|
||||
// Füge Hausnummer hinzu, wenn vorhanden
|
||||
if (geoResult.housenumber) {
|
||||
addressParts.push(geoResult.housenumber);
|
||||
}
|
||||
|
||||
// Füge Straße hinzu, wenn vorhanden
|
||||
if (geoResult.street) {
|
||||
addressParts.push(geoResult.street);
|
||||
}
|
||||
|
||||
// Kombiniere Hausnummer und Straße
|
||||
let address = addressParts.join(' ');
|
||||
|
||||
// Füge Namen hinzu, wenn vorhanden
|
||||
if (geoResult.name) {
|
||||
address = address ? `${address}, ${geoResult.name}` : geoResult.name;
|
||||
}
|
||||
|
||||
// Füge County hinzu, wenn vorhanden
|
||||
if (geoResult.county) {
|
||||
address = address ? `${address}, ${geoResult.county}` : geoResult.county;
|
||||
}
|
||||
|
||||
// Füge Bundesland hinzu, wenn vorhanden
|
||||
if (geoResult.state) {
|
||||
address = address ? `${address} - ${geoResult.state}` : geoResult.state;
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
formatPlaceAddress(place: Place | null | undefined): string {
|
||||
// Überprüfen, ob place null oder undefined ist
|
||||
if (!place) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const { house_number, road, city, county, state } = place.address;
|
||||
|
||||
let addressParts: string[] = [];
|
||||
|
||||
// Füge Hausnummer hinzu, wenn vorhanden
|
||||
if (house_number) {
|
||||
addressParts.push(house_number);
|
||||
}
|
||||
|
||||
// Füge Straße hinzu, wenn vorhanden
|
||||
if (road) {
|
||||
addressParts.push(road);
|
||||
}
|
||||
|
||||
// Kombiniere Hausnummer und Straße
|
||||
let address = addressParts.join(' ');
|
||||
|
||||
// Füge Stadt hinzu, wenn vorhanden
|
||||
if (city) {
|
||||
address = address ? `${address}, ${city}` : city;
|
||||
}
|
||||
|
||||
// Füge County hinzu, wenn vorhanden
|
||||
if (county) {
|
||||
address = address ? `${address}, ${county}` : county;
|
||||
}
|
||||
|
||||
// Füge Bundesland hinzu, wenn vorhanden
|
||||
if (state) {
|
||||
address = address ? `${address} - ${state}` : state;
|
||||
}
|
||||
|
||||
return address;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user