Skip to content

Conversation

latin-panda
Copy link
Collaborator

Closes #305

WIF

I have verified this PR works in these browsers (latest versions):

  • Chrome
  • Firefox
  • Safari (macOS)
  • Safari (iOS)
  • Chrome for Android
  • Not applicable

What else has been done to verify that this works as intended?

Why is this the best possible solution? Were any other approaches considered?

How does this change affect users? Describe intentional changes to behavior and behavior that could have accidentally been affected by code changes. In other words, what are the regression risks?

Do we need any specific form for testing your changes? If so, please attach one.

What's changed

Copy link

changeset-bot bot commented Aug 25, 2025

⚠️ No Changeset found

Latest commit: 0cd76eb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

type DerivedItemLabel = ClientTextRange<'item-label', 'form-derived'>;
export interface BaseItem {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Start in this file

This is the simple base item for Rank and Select.

Select's item will include geometry and metadata. The latter contains everything defined in the choice sheet from an XLS form, except for the value's column (usually called "name", but it can be another column), itextId, and geometry, to prevent duplicate data in Select's item.

@@ -101,6 +102,8 @@ const createItemsetItemLabel = (
interface ItemsetItem {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If rank and <item> require geometry and metadata, then we can use only this interface and remove BaseItem.

I think <item> needs geometry and metadata, but rank does not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, there is no situation in which the frontend needs additional properties on rank items. Those additional properties might be used in choice filters or calculations but that's all handle engine-side.

defaultValue: '',
});

const nodeElements = itemNode
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The itemNode already includes everything from the choice sheet. Here, we follow the same approach as with "value" (L123).

@@ -144,6 +166,8 @@ const createItemset = (
return {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the data is extracted, and the Vue client receives:

Image

import type { ItemsetElement } from '../../../lib/dom/query.ts';
import { getValueElement } from '../../../lib/dom/query.ts';
import { ItemsetGeometryExpression } from '../../expression/ItemsetGeometryExpression.ts';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These expressions (ItemsetGeometryExpression, ItemsetMetadataExpression, ItemsetNodesetExpression, and ItemsetValueExpression) could be removed and replaced with DependentExpression directly.

While ItemsetLabelDefinition can stay, it has more complexity to encapsulate.

this.value = new ItemsetValueExpression(this, valueExpression);
this.geometry = new ItemsetGeometryExpression(this);

this.metadataExclusions = ['itextId', this.value.expression, this.geometry.expression];
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted earlier, I aim to exclude anything already exposed as a class attribute to prevent data duplication and simplify the Vue client’s looping and rendering work.

.filter((node) => node.nodeType === 'static-element');
const metadata = itemset.getMetadataExpressions(nodeElements).map((meta) => {
return {
label: meta.elementName,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this translatable or does it have media? Otherwise it will need to be a TextRange

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the values of additional properties, right? Currently these are not translatable -- each property/column is independent from the others.

@latin-panda latin-panda changed the title feat(#305):Select one for map feat(#305):Select one for map - xforms-engine Aug 25, 2025
get value(): string;
export interface SelectItem extends BaseItem {
geometry?(): string;
metadata?: Array<{ label: string; value(): string }>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

properties or additionalProperties?

geometry could also simply be an additionalProperty.

But that makes me think -- in what format is the geometry value right now when items are from a geoJSON file? Ideally the engine exposes a consistent format so the client doesn't have to do any conversion.

If geometry is made into its own concept, we should use a type to describe/validate/represent the structure rather than a raw string.

Copy link
Member

@lognaturel lognaturel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't had a chance to think about this in detail quite yet. I think the key question is what to expose to the client. Some of the big questions I see:

  • Is geometry a first-class concept? In JavaRosa/Collect, it's not something JR knows about, it's just passed as part of an "additional properties" list and Collect pulls it out.
  • What format should the geometry value be exposed in? In Collect/JR, it's always in ODK format, even when from geoJSON

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add select one from map question type
2 participants