npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@polar/plugin-address-search

v2.0.0

Published

AddressSearch plugin for POLAR that adds a user interface to search for various kinds of textual information to map it to a geometry; e.g. parcel numbers or addresses, but any kind of toponym mapping is possible.

Downloads

1,582

Readme

AddressSearch

Scope

The AddressSearch plugin allows users to search for an address. If multiple addresses are returned by services, the user is prompted to select a result.

The plugin saves the chosen information as GeoJSON to the store so that following procedures may grab it or so that other plugins may use it.

Currently supported services:

  • BKG
  • WFS
  • Hamburg WFS-G (mpapi), may fit some WFS-G outside HH, test advised

Configuration

addressSearch

The configuration allows defining and grouping services. Grouped services can be requested in a search at the same time, and one group of searches can be active at a time. When multiple searches are in a group, they may be extended with category information to make the results easier to browse.

It is advised to either use one-search-per-group or all services in a singular group to avoid an overly complex UI. Mixed configurations may be required for more complex search requirements.

In categoryProperties and groupProperties, id strings called groupId and categoryId are used. These are arbitrary strings you can introduce and reuse to group or categorize elements together. Regarding what groups and categories are, see further below.

| fieldName | type | description | | - | - | - | | searchMethods | searchMethodsObject[] | Array of search method descriptions. Only searches configured here can be used. | | addLoading | string? | Expects the path to a mutation within the store. This mutation is committed with a plugin-specific loading key as payload when starting asynchronous procedures that are intended to be communicated to the user. | | afterResultComponent | VueConstructor? | If given, this component will be rendered in the last line of every single search result. It will be forwarded its search result feature as prop feature of type GeoJSON.Feature, and the focus state of the result as prop focus of type boolean. | | categoryProperties | Record<string, categoryProperties>? | An object defining properties for a category. The searchMethod's categoryId is used as identifier. A service without categoryId does not have a fallback category. | | customSearchMethods | Record<string, customSearchMethod>? | An object with named search functions added to the existing set of configurable search methods. (See addressSearch.searchMethodsObject.type) This record's keys are added to that enum. | | customSelectResult | Record<string, customSelectFunction>? | An object that maps categoryIds to functions. These functions are then called as vuex store actions instead of the selectResult default implementation. This allows overriding selection behaviour with full store access. Use '' as key for categoryless results. | | focusAfterSearch | boolean? | Whether the focus should switch to the first result after a successful search. Defaults to false. | | groupProperties | Record<string, groupProperties>? | An object defining properties for a group. The searchMethod's groupId is used as identifier. All services without groupId fall back to the key "defaultGroup". | | minLength | number? | Minimal input length after which searches are started. Defaults to 0. | | removeLoading | string? | Expects the path to a mutation within the store. This mutation is committed with a plugin-specific loading key as payload when finishing asynchronous procedures that are intended to be communicated to the user. | | waitMs | number? | Debounce time in ms for search requests after last user input. Defaults to 0. |

For details on the displayComponent attribute, refer to the Global Plugin Parameters section of @polar/core.

import Component from './component.vue'

addressSearch: {
  searchMethods: [
    {
      queryParameters: {
        searchAddress: true,
        searchStreets: true,
        searchHouseNumbers: true,
      },
      type: 'mpapi',
      url: 'example-url.com',
    },
    {
      queryParameters: {
        filter: {
          bundesland: 'Schleswig-Holstein',
        },
      },
      type: 'bkg',
      url: 'other-example-url.com',
    },
    {
      type: 'wfs'
      queryParameters: {
        srsName: 'EPSG:25832',
        typeName: 'address_shp',
        fieldName: 'objektid',
        featurePrefix: 'app',
        xmlns: 'http://www.deegree.org/app',
        useRightHandWildcard: true,
      },
    }
  ],
  afterResultComponent: Component,
  groupProperties: {
    defaultGroup: {
      limitResults: 5,
    },
  },
  focusAfterSearch: true,
  minLength: 3,
  waitMs: 300,
  addLoading: 'plugin/loadingIndicator/addLoadingKey',
  removeLoading: 'plugin/loadingIndicator/removeLoadingKey',
},

addressSearch.searchMethodsObject

| fieldName | type | description | | - | - | - | | type | enum["bkg", "wfs", "mpapi"] | Service type. Enum can be extended by configuration, see addressSearch.customSearchMethods. | | url | string | Search service URL. Should you require a service provider, please contact us for further information. | | categoryId | string? | Grouped services can optionally be distinguished in the UI with categories. See addressSearch.categoryProperties for configuration options. | | groupId | string? | Default groupId is "defaultGroup". All services with the same id are grouped and used together. See addressSearch.groupProperties for configuration options. If multiple groups exist, the UI offers a group switcher. | | hint | string? | Hint that is displayed below the input field if no other plugin-state-based hint is to be displayed. Can be a locale key. If grouped with other services, the group's hint will be used instead. | | label | string? | Display label. Can be a locale key. If grouped with other services, the group's label will be used instead. | | placeholder | string? | Placeholder string to display on input element. Can be a locale key. If grouped with other services, the group's placeholder will be used instead. | | queryParameters | object? | The object further describes details for the search request. Its contents vary by service type, see documentation below. |

Example configuration:

 searchMethods: [
  {
    groupId: 'groupAdressSearch',
    categoryId: 'categoryAddressSearch',
    type: 'bkg',
    url: 'example.com',
    hint: 'Input of e.g. street or address',
    label: 'Street search',
    placeholder: 'Street name',
    queryParameters: {
      filter: {
        bundesland: 'Schleswig-Holstein',
      },
    },
  },
],

#### addressSearch.customSearchMethod

This is a function with the following signature:

```ts
(
  // should be used to actually abort request
  signal: AbortSignal,
  // base url as configured
  url: string,
  // input value from address search input
  inputValue: string,
  // whatever was configured
  queryParameters: any
) => Promise<FeatureCollection> | never

With this, arbitrary services can be supported.

addressSearch.customSelectFunction

This is a function with the following signature:

({
  // VueX context object
  context,
  payload: {
    feature, // GeoJSON feature
    categoryId // if configured on searchService, else ''
  }
}) => void

With this, arbitrary click results can be supported. Please mind that undocumented mutations and actions fired in such a function are subject to change without further notice.

addressSearch.groupProperties

| fieldName | type | description | | - | - | - | | label | string | Display label. Can be a locale key. | | resultDisplayMode | enum['mixed', 'categorized'] | Defaults to 'mixed'. In 'mixed', results of all requested services are offered in a list in no specific order. In 'categorized', the results are listed by their searchService's categoryId. | | hint | string? | Hint that is displayed below the input field if no other plugin-state-based hint is to be displayed. Can be a locale key. | | limitResults | number? | If set, only the first n results (per category in categorized) are displayed initially. All further results can be opened via UI. | | placeholder | string? | Placeholder string to display on input element. Can be a locale key. |

Example configuration:

groupProperties: {
  groupAdressSearch: {
    label: 'Street search',
    hint: 'Please enter a street name',
    resultDisplayMode: 'categorized',
    limitResults: 3,
  },
  defaultGroup: {
    limitResults: 5,
  },
}

addressSearch.categoryProperties

| fieldName | type | description | | - | - | - | | label | string | Category label to display next to results to identify the source. Can be a locale key. Only relevant if the search's groupProperties linked via groupId contain a resultDisplayMode scenario that uses categories. |

Example configuration:

categoryProperties: {
  categoryAddressSearchAutocomplete: {
    label: 'Address search hits',
  },
}
addressSearch.searchMethodsObject.queryParameters (type:common)

These fields are interpreted by all implemented services.

| fieldName | type | description | | - | - | - | | maxFeatures | number? | Maximum amount of features to retrieve. Doesn't limit results if not set. |

Example configuration:

queryParameters: {
  maxFeatures: 120,
},
addressSearch.searchMethodsObject.queryParameters (type:wfs)

| fieldName | type | description | | - | - | - | | featurePrefix | string | XML feature prefix for WFS service. | | typeName | string | Feature type to search for by name. | | xmlns | string | XML namespace to use in search. | | fieldName | string? | Name of the type's field to search in. Mutually exclusive to patterns. | | likeFilterAttributes | Record<string, string>? | As specified by the OGC-Standard for filters the PropertyIsLike operator requires three attributes (e.g. in WFS 2.0.0: wildCard, singleChar and escapeChar). These may vary in value and (with other WFS versions) also in property definition. Therefore, it is possible to configure the values of the attributes needed for WFS 2.0.0 and also to add custom attributes needed for other versions. Defaults to {wildCard: "\*", singleChar: ".", escapeChar: "!"}. | | patternKeys | Record<string, string>? | Maps field names from patterns to regexes. Each field name has to have a definition. Each regex must have one capture group that is used to search. Contents next to it are ignored for the search and just used for matching. E.g. '([0-9]+)$' would be a value for a key that fits an arbitrary number string at the input's end. | | patterns | string[]? | Allows specifying input patterns. In a single-field search, a pattern can be as easy as {{theWholeThing}}, where theWholeThing is also the feature field name to search in. In more complex scenarios, you may add separators and multiple fields, e.g. {{gemarkung}} {{flur}} {{flstnrzae}}/{{flstnrnen}} would fit many parcel search services. Mutually exclusive to fieldName. | | srsName | string? | Name of the projection (srs) for the query. | | useRightHandWildcard? | boolean? | By default, if searching for "search", it is sent as "search*". This behaviour can be deactivated by setting this parameter to false. |

Since inputs may overlap with multiple patterns, multiple queries are fired and executed on the WFS until the maxFeatures requirement is met, beginning with the pattern that 'looks like the user input the most'. The best-fitting pattern on the returned features will be used to generate a display string. When two patterns fit best, the first one is used.

Configuration examples for the likeFilterAttributes parameter:

  • WFS 2.0.0 {wildCard: "%", singleChar: "*", escapeChar: "\"}
  • WFS 1.0.0 {wildCard: "*", singleChar: "*", escape: "\"}

Example configurations:

type: 'wfs'
queryParameters: {
  srsName: 'EPSG:25832',
  typeName: 'address_shp',
  fieldName: 'objektid',
  featurePrefix: 'app',
  xmlns: 'http://www.deegree.org/app',
  useRightHandWildcard: true,
}
type: 'wfs'
queryParameters: {
  srsName: 'EPSG:25832',
  typeName: 'address_shp',
  featurePrefix: 'app',
  xmlns: 'http://www.deegree.org/app',
  patternKeys: {
    streetName: '([A-Za-z]+)'
    houseNumber: '([0-9]+)'
    postalCode: '([0-9]+)'
    city: '([A-Za-z]+)'
  },
  patterns: [
    '{{streetName}} {{houseNumber}} {{postalCode}} {{city}}' 
  ]
}
addressSearch.searchMethodsObject.queryParameters (type:mpapi)

Please mind that this requires a configured backend. A WFS's Stored Query is requested with predefined parameters using the masterportalapi. This implementation is meant for e.g. https://geodienste.hamburg.de/HH_WFS_GAGES, but works with other WFS configured in the same manner.

| fieldName | Type | Description | | - | - | - | | searchAddress | Boolean? | Defines whether address search is active. For backward compatibility, if "searchAddress" is not configured, the "searchAddress" attribute is set to "true" when "searchStreets" and "searchHouseNumbers" are set to "true". | | searchDistricts | Boolean? | Defines whether district search is active. | | searchHouseNumbers | Boolean? | Defines whether house numbers should be searched for. Requires searchStreets to be set to true, too. | | searchParcels | Boolean? | Defines whether parcels search is active. | | searchStreetKey | Boolean? | Defines whether streets should be searched for by key. | | searchStreets | Boolean? | Defines whether street search is active. Precondition to set searchHouseNumbers to true. |

While all fields are optional, configuring none of them will yield undefined behaviour. At least one search instruction should be set to true.

type: 'mpapi'
queryParameters: {
  searchAddress: true,
  searchStreets: true,
  searchHouseNumbers: true,
},
addressSearch.searchMethodsObject.queryParameters (type:bkg)

In BKG mode, queryParameter's key-value pairs are used in the service query. E.g. {filter: { bundesland: 'Bremen' }} results in the GET request URL having &filter=bundesland:Bremen as suffix.

For more options, please check the official documentation regarding what query parameters are interpreted.

Additionally, it is possible to configure the parameters accesstoken (Authorization) or apiKey (custom header X-Api-Key) to send the described headers to the search service for authentication purposes. Note that this changes the request to be non-simple. To be able to use the parameters, the request has to be sent in cors mode and has to support preflight request OPTIONS.

type: 'bkg'
queryParameters: {
  filter: {
    bundesland: 'Schleswig-Holstein',
  },
},

Store

Mutations

setSelectedGroupName

This can be used to change the selected search group by name.

map.$store.commit(
  'plugin/addressSearch/setSelectedGroupName',
  'Parcel search'
)

Please mind that programmatically changing the search group will not trigger a search, unlike a search group change by the user. If you need a search after change, consider the search action.

Actions

search

This is a purely programmatical search method. It is not used by user input.

map.$store.dispatch('plugin/addressSearch/search', {
  input: 'Station Road 12',
  autoselect: 'first',
})

The payload object supports the following fields:

| fieldName | type | description | | - | - | - | | input | string | Search string to be used. | | autoselect | enum['first', 'only', 'never'] | By default, 'never' is selected, and results will be presented as if the user searched for them. Setting 'only' will autoselect if a single result was returned; setting 'first' will autoselect the first of an arbitrary amount of results >=1. |

State

map.subscribe('plugin/addressSearch/chosenAddress', (chosenAddress) => {
  /* Your code. */
})

Address object as returned by search service. The result and its fields differ depending on the used backend. The callback is used whenever the user clicks on a search result or started a one-result search, which results in an auto-select of the singular result.