diff --git a/projects/hslayers/components/wfs-filter/wfs-filter.component.html b/projects/hslayers/components/wfs-filter/wfs-filter.component.html index 9c97a63a6a..cb87f17f81 100644 --- a/projects/hslayers/components/wfs-filter/wfs-filter.component.html +++ b/projects/hslayers/components/wfs-filter/wfs-filter.component.html @@ -1 +1,61 @@ - \ No newline at end of file +
+ + @if (availableLayers.length > 0) { + +
+
+ + +
+
+ + + @if (selectedLayer) { +
+
+
+
+
Filter for: {{ selectedLayer.title }}
+ + +
+
+
+
+ } @else { + +
+
+ +
+
+ } + } @else { + +
+
+
+ +

No WFS Layers Available

+

There are currently no WFS layers available for filtering.

+

To use this feature, please add a WFS layer to the map first.

+ + +
+
+
+ } +
\ No newline at end of file diff --git a/projects/hslayers/components/wfs-filter/wfs-filter.component.ts b/projects/hslayers/components/wfs-filter/wfs-filter.component.ts index ef35e2d5c7..c2ead19d84 100644 --- a/projects/hslayers/components/wfs-filter/wfs-filter.component.ts +++ b/projects/hslayers/components/wfs-filter/wfs-filter.component.ts @@ -1,49 +1,120 @@ import * as olFormatFilter from 'ol/format/filter'; -import {Component, Input, inject} from '@angular/core'; -import { - HsFiltersComponent, - HsFiltersService, -} from 'hslayers-ng/components/styler'; +import {Component, Input, OnInit, inject} from '@angular/core'; +import {FormsModule} from '@angular/forms'; +import {HsFiltersComponent, HsFiltersService} from 'hslayers-ng/common/filters'; +import {HsLayerDescriptor} from 'hslayers-ng/types'; +import {HsLayerManagerService} from 'hslayers-ng/services/layer-manager'; +import {HsLayoutService} from 'hslayers-ng/services/layout'; +import {HsUtilsService} from 'hslayers-ng/services/utils'; +import {Vector as VectorLayer} from 'ol/layer'; +import {Vector as VectorSource} from 'ol/source'; +import {getWfsUrl} from 'hslayers-ng/common/extensions'; @Component({ selector: 'hs-wfs-filter', templateUrl: './wfs-filter.component.html', styles: ``, standalone: true, - imports: [HsFiltersComponent], + imports: [HsFiltersComponent, FormsModule], }) -export class HsWfsFilterComponent { - @Input() rule: any; +export class HsWfsFilterComponent implements OnInit { + @Input() rule: any = {}; + @Input() preselectedLayer: HsLayerDescriptor; hsFiltersService = inject(HsFiltersService); - constructor() {} - - parseFilters(filters: any[]): any[] { - return filters.map((filter) => { - switch (filter[0]) { - case '==': - return olFormatFilter.equalTo(filter[1], filter[2]); - case '*=': - return olFormatFilter.like(filter[1], filter[2]); - case '!=': - return olFormatFilter.notEqualTo(filter[1], filter[2]); - case '<': - return olFormatFilter.lessThan(filter[1], filter[2]); - case '<=': - return olFormatFilter.lessThanOrEqualTo(filter[1], filter[2]); - case '>': - return olFormatFilter.greaterThan(filter[1], filter[2]); - case '>=': - return olFormatFilter.greaterThanOrEqualTo(filter[1], filter[2]); - case '&&': - return olFormatFilter.and(...this.parseFilters(filter.slice(1))); - case '||': - return olFormatFilter.or(...this.parseFilters(filter.slice(1))); - case '!': - return olFormatFilter.not(this.parseFilters([filter[1]])[0]); - default: - throw new Error('Invalid filter type'); - } - }); + hsLayerManagerService = inject(HsLayerManagerService); + hsUtilsService = inject(HsUtilsService); + hsLayoutService = inject(HsLayoutService); + + availableLayers: HsLayerDescriptor[] = []; + selectedLayer: HsLayerDescriptor | null = null; + + ngOnInit() { + this.updateAvailableLayers(); + if (this.preselectedLayer) { + this.selectLayer(this.preselectedLayer); + } + } + + /** + * Updates the list of available WFS layers + */ + updateAvailableLayers() { + this.availableLayers = this.hsLayerManagerService.data.layers.filter( + (l: HsLayerDescriptor) => + this.hsUtilsService.instOf(l.layer, VectorLayer) && + this.hsUtilsService.instOf(l.layer.getSource(), VectorSource) && + getWfsUrl(l.layer), + ); + } + + /** + * Selects a layer and updates the filter service + * @param layer The layer to select + */ + selectLayer(layer: HsLayerDescriptor | null) { + this.selectedLayer = layer; + this.hsFiltersService.setSelectedLayer(layer); + // Reset the rule when changing layers + this.rule = {}; + } + + /** + * Handles changes in the filter + */ + onChange() { + if (this.rule.filter) { + const parsedFilter = this.parseFilter(this.rule.filter); + console.log('Parsed OpenLayers filter for WFS:', parsedFilter); + // You can now use this parsedFilter with OpenLayers for WFS requests + } + } + + /** + * Parses the filter into OpenLayers format + * @param filter The filter to parse + * @returns Parsed OpenLayers filter + */ + parseFilter(filter: any[]): any { + if (!Array.isArray(filter)) { + return null; + } + + const [operator, ...operands] = filter; + + switch (operator) { + case '||': + return olFormatFilter.or(...operands.map((op) => this.parseFilter(op))); + case '&&': + return olFormatFilter.and( + ...operands.map((op) => this.parseFilter(op)), + ); + case '!': + return olFormatFilter.not(this.parseFilter(operands[0])); + case '==': + return olFormatFilter.equalTo(operands[0], operands[1]); + case '*=': + return olFormatFilter.like(operands[0], operands[1]); + case '!=': + return olFormatFilter.notEqualTo(operands[0], operands[1]); + case '<': + return olFormatFilter.lessThan(operands[0], operands[1]); + case '<=': + return olFormatFilter.lessThanOrEqualTo(operands[0], operands[1]); + case '>': + return olFormatFilter.greaterThan(operands[0], operands[1]); + case '>=': + return olFormatFilter.greaterThanOrEqualTo(operands[0], operands[1]); + default: + console.warn(`Unsupported operator: ${operator}`); + return null; + } + } + + /** + * Opens the Add Data panel + */ + openAddDataPanel() { + this.hsLayoutService.setMainPanel('addData'); } } diff --git a/projects/hslayers/services/styler/public-api.ts b/projects/hslayers/services/styler/public-api.ts index 110720e122..f2dd0e2397 100644 --- a/projects/hslayers/services/styler/public-api.ts +++ b/projects/hslayers/services/styler/public-api.ts @@ -1,2 +1,3 @@ export * from './styler.service'; export * from './default-style'; +export * from './style-part-base.component'; diff --git a/projects/hslayers/services/styler/style-part-base.component.ts b/projects/hslayers/services/styler/style-part-base.component.ts new file mode 100644 index 0000000000..ef3a911709 --- /dev/null +++ b/projects/hslayers/services/styler/style-part-base.component.ts @@ -0,0 +1,20 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; + +@Component({ + template: '
', + standalone: true, +}) +export class HsStylerPartBaseComponent { + @Output() changes = new EventEmitter(); + @Output() deleteFilter = new EventEmitter(); + + @Input() warning: string; + + emitChange(): void { + this.changes.emit(); + } + + deleteRuleFilter(): void { + this.deleteFilter.emit(); + } +}