Summary
Add a URL parameter that lets an external application deep-link into QWC2 and, on load, select and identify one or several features of a given layer by the value(s) of an arbitrary attribute : highlighting them, zooming to them, and opening the Identify panel with their attributes.
This extends the existing identifySearchResults option (77d9e85) from the single, point-based case to a multi-feature, filter-based one.
Motivation
External business applications need to hand a user off to a map, passing a reference to one or more objects. That reference is a business identifier carried in the external system (a parcel number, an asset id, a tree number...) which:
- may live in any attribute column, not necessarily the layer's primary key, so the column has to be specifiable in the URL; and
- is often not unique, so a single reference can resolve to several features. Selecting a list is therefore the general case, not an edge case.
The expected result: land in the theme with the matching features highlighted, the map zoomed to them, and their attributes visible in the Identify panel.
Existing approaches (and why they fall short)
QWC2 already exposes three URL-driven ways to deep-link into a theme (see the Interfacing docs). None cleanly does both point at a business identifier (or a list) and select + identify the matching features.
1. Generic search — st (+ optional sp provider). SearchBox runs the theme's search provider(s) on st; a single place result auto-selects (selectPlaceResult), highlighting + zooming (showResultGeometry), and opens Identify with identifySearchResults: true. But: needs a configured provider, it's a fuzzy text match (not an exact attribute lookup), and only a single result triggers it — no list.
2. Fulltext-search service — hp + hf/st. The only path built for highlight-by-reference: FulltextSearch.handleHighlightParameters queries the data-service, highlights + zooms, and opens Identify with identifySearchResults: true. But: hard-gated behind searchServiceUrl + dataServiceUrl (services EMS does not deploy), hf is verbose JSON ([["field","=",value]]), and the Identify is point-based at the bbox centre — fragile for polygons/lines, and wrong for a list.
3. Theme WMS filter — f (MapFilter plugin). f is a JSON blob the MapFilter plugin turns into a server-side WMS FILTER (SET_FILTER). This is the current workaround we use and it works with no extra service:
?t=ems_test&f=%7B%22__custom%22%3A%5B%7B%22title%22%3A%22Parcelle%22%2C%22layer%22%3A%22parcelles%22%2C%22expr%22%3A%5B%22id_parcellaire%22%2C%22%3D%22%2C%22674820470136%22%5D%7D%5D%7D
where the decoded f is:
{"__custom": [{"title": "Parcelle", "layer": "parcelles", "expr": ["id_parcellaire", "=", "674820470136"]}]}
A list even works out of the box — "expr": ["id_parcellaire", "IN", ["674820470136", "674820470137"]] serializes to IN ( … ). But: it hides non-matching features instead of highlighting them, never zooms or opens Identify, needs verbose JSON, and its IN serialization leaves values unquoted (so numeric-looking ids only).
Proposed solution
A dedicated URL parameter, in the spirit of the existing QGIS Web parameters (t, l, …), of the form:
?t=<theme>&<param>=<layer>:<field>:<value1>,<value2>,…
On theme load, the viewer would:
- parse the parameter and build an attribute filter of the form
<layer>:"<field>" IN ( <v1> , <v2> , … ) (no JSON in the URL)
- issue a single GetFeatureInfo request carrying that expression as the WMS
FILTER parameter (via QGIS Server), returning every matching feature with geometry and attributes (plus the maptip HTML, if the layer defines one);
- populate the
IdentifyViewer (multi-feature tree + attribute tables / maptips) and open the panel;
- highlight all matching features (
highlightAllResults) and zoom to the aggregated bbox.
A single FILTER-based identify covers highlighting and attributes in one path. It is robust (no centroid guessing), does not depend on the search/data services, handles the single-value case as a list of length one, and handles the primary-key case for free (the field can be the PK). The building blocks (buildFilterRequest, the IdentifyViewer multi-feature tree, highlightAllResults) already exist.
Open questions
- Parameter name and syntax : what fits the existing URL-parameter conventions best?
- List size : should there be a cap on the number of values, given URL-length and performance/permission considerations, and the server's default
feature_count: 100?
- Relation to
hp/hf : introduce a new, non-verbose parameter and keep hp/hf as-is, or extend the existing ones?
Happy to implement this and open a PR once there's agreement on the parameter design.
Summary
Add a URL parameter that lets an external application deep-link into QWC2 and, on load, select and identify one or several features of a given layer by the value(s) of an arbitrary attribute : highlighting them, zooming to them, and opening the Identify panel with their attributes.
This extends the existing
identifySearchResultsoption (77d9e85) from the single, point-based case to a multi-feature, filter-based one.Motivation
External business applications need to hand a user off to a map, passing a reference to one or more objects. That reference is a business identifier carried in the external system (a parcel number, an asset id, a tree number...) which:
The expected result: land in the theme with the matching features highlighted, the map zoomed to them, and their attributes visible in the Identify panel.
Existing approaches (and why they fall short)
QWC2 already exposes three URL-driven ways to deep-link into a theme (see the Interfacing docs). None cleanly does both point at a business identifier (or a list) and select + identify the matching features.
1. Generic search —
st(+ optionalspprovider).SearchBoxruns the theme's search provider(s) onst; a single place result auto-selects (selectPlaceResult), highlighting + zooming (showResultGeometry), and opens Identify withidentifySearchResults: true. But: needs a configured provider, it's a fuzzy text match (not an exact attribute lookup), and only a single result triggers it — no list.2. Fulltext-search service —
hp+hf/st. The only path built for highlight-by-reference:FulltextSearch.handleHighlightParametersqueries the data-service, highlights + zooms, and opens Identify withidentifySearchResults: true. But: hard-gated behindsearchServiceUrl+dataServiceUrl(services EMS does not deploy),hfis verbose JSON ([["field","=",value]]), and the Identify is point-based at the bbox centre — fragile for polygons/lines, and wrong for a list.3. Theme WMS filter —
f(MapFilter plugin).fis a JSON blob theMapFilterplugin turns into a server-side WMSFILTER(SET_FILTER). This is the current workaround we use and it works with no extra service:where the decoded
fis:{"__custom": [{"title": "Parcelle", "layer": "parcelles", "expr": ["id_parcellaire", "=", "674820470136"]}]}A list even works out of the box —
"expr": ["id_parcellaire", "IN", ["674820470136", "674820470137"]]serializes toIN ( … ). But: it hides non-matching features instead of highlighting them, never zooms or opens Identify, needs verbose JSON, and itsINserialization leaves values unquoted (so numeric-looking ids only).Proposed solution
A dedicated URL parameter, in the spirit of the existing QGIS Web parameters (
t,l, …), of the form:On theme load, the viewer would:
<layer>:"<field>" IN ( <v1> , <v2> , … )(no JSON in the URL)FILTERparameter (via QGIS Server), returning every matching feature with geometry and attributes (plus the maptip HTML, if the layer defines one);IdentifyViewer(multi-feature tree + attribute tables / maptips) and open the panel;highlightAllResults) and zoom to the aggregated bbox.A single FILTER-based identify covers highlighting and attributes in one path. It is robust (no centroid guessing), does not depend on the search/data services, handles the single-value case as a list of length one, and handles the primary-key case for free (the field can be the PK). The building blocks (
buildFilterRequest, theIdentifyViewermulti-feature tree,highlightAllResults) already exist.Open questions
feature_count: 100?hp/hf: introduce a new, non-verbose parameter and keephp/hfas-is, or extend the existing ones?Happy to implement this and open a PR once there's agreement on the parameter design.