Select to view content in your preferred language

Editor WebComponent access viewModel.featureTemplatesViewModel.filterFunction

208
2
Jump to solution
a month ago
SebastianKrings
Frequent Contributor

Using the old way of the Editor Widget wir used a filter function to exclude specific layers from the "front-page" of the EditorWidget while keeping the ability to still edit features of these layers.

This is how we successfully did that:

    [...]
    this._activeEditor = new Editor({
        view: mapView,
        container: this.canvasId,
        layerInfos
    });

    this._activeEditor.when(() => {
        this.setFeatureTemplatesFilterAsync();
    });
}

private async setFeatureTemplatesFilterAsync() {
    const excludedTitles = await this._schema.getLayerNamesFromKeysAsync([LshLayerKeysEnum.CavePolygons, LshLayerKeysEnum.RoutingPositions]) ?? [];

    this._activeEditor!.viewModel.featureTemplatesViewModel.filterFunction = (item) => {
        return !excludedTitles.some(title => item?.label?.startsWith(title));
    };
}


Now after changing to new web component I am asking myseld how to set the filterFunction or how to access the viewModel.


This is how it currently looks without setting the filterFunction.

 

<arcgis-editor
    reference-element="my-map"
    [layerInfos]="layerInfos()">
</arcgis-editor>

 

 

0 Kudos
1 Solution

Accepted Solutions
SebastianKrings
Frequent Contributor

I found a way to access it, but since the Editor-Type is still deprecated I guess this is not a good long-term way.

Any suggestions here?

const editorElement = document.querySelector('arcgis-editor') as (HTMLElement & {
    componentOnReady?: () => Promise<void>;
    widget?: Editor;
}) | null;

if (!editorElement) {
    return;
}

if (typeof editorElement.componentOnReady === 'function') {
    await editorElement.componentOnReady();
}

const editorWidget = editorElement.widget;
if (!editorWidget?.viewModel?.featureTemplatesViewModel) {
    return;
}

editorWidget.viewModel.featureTemplatesViewModel.filterFunction = item => {
    return !excludedTitles.some(title => item?.label?.startsWith(title));
};

 

Edit: This Template Solution does not work, because, when creating one of these excluded Features via Relation of another non-excluded Feature, they are not selectable.

SebastianKrings_0-1779194735911.png

 

SebastianKrings_1-1779194744992.png

So the dirty DOM Solution is the one to choose.

As an dirty alternative we also found another (more future reliable way) by DOM manipulation:

/**
 * Observes the ArcGIS Editor shadow DOM for runtime UI updates.
 * The ArcGIS Editor dynamically rebuilds its internal DOM structure.
 * Therefore hidden create entries would reappear after rerendering
 * without a MutationObserver.
 * This observer listens for DOM changes and reapplies the
 * create-entry hiding logic whenever the editor updates itself.
 */
private observeEditorDom() {

	// Get the ArcGIS editor web component
	const editor = document.querySelector(
		'arcgis-editor'
	) as HTMLElement | null;

	// Abort if the shadow DOM is not available yet
	if (!editor?.shadowRoot) {
		return;
	}

	const root = editor.shadowRoot;

	// Reapply hiding logic whenever the editor rerenders
	const observer = new MutationObserver(() => {
		this.hideConfiguredCreateEntriesAsync(root);
	});

	// Observe the complete editor subtree for changes
	observer.observe(root, {
		childList: true,
		subtree: true
	});

	// Initial execution after observer registration
	this.hideConfiguredCreateEntriesAsync(root);
}

/**
 * Hides configured layer create entries from the ArcGIS Editor UI.
 * Important:
 * - Only the visible UI entries are hidden
 * - Layers/templates remain fully functional internally
 * - Related feature creation therefore still works
 * The method only targets the "Create Features" section.
 * Related feature dialogs are ignored automatically because they
 * use a different DOM structure.
 * @Param root Shadow root of the ArcGIS Editor component
 */
private async hideConfiguredCreateEntriesAsync(root: ShadowRoot) {

	// Get currently active flow item inside the editor
	const selectedFlowItem = root.querySelector(
		'calcite-flow-item[selected]'
	) as HTMLElement | null;

	// Only the Create Features Section contains this container.
	// Related feature dialogs do not contain it.
	const createTemplatesContainer = selectedFlowItem?.querySelector(
		'.esri-editor__feature-templates-container'
	);

	// Abort if current view is not the create-features screen
	if (!selectedFlowItem || !createTemplatesContainer) {
		return;
	}

	// Resolve layer names dynamically via schema configuration
	const hiddenEntryNames =
		...) ?? [];

	// Collect all create-entry groups rendered by ArcGIS
	const groups = Array.from(
		createTemplatesContainer.querySelectorAll(
			'.esri-item-list__group'
		)
	).filter(
		(element): element is HTMLElement =>
			element instanceof HTMLElement
	);

	// Iterate through all rendered create groups
	for (const group of groups) {

		// Extract the visible heading text
		const groupHeading = group.querySelector(
			'.esri-widget__heading'
		);

		const groupHeadingText = groupHeading
			?.textContent
			?.trim();

		// Skip invalid entries
		if (!groupHeadingText) {
			continue;
		}

		// Check whether current group should be hidden
		const shouldHide = hiddenEntryNames.some(
			hiddenName => groupHeadingText === hiddenName
		);

		// Skip unrelated or already hidden groups
		if (!shouldHide || group.dataset['createEntryHidden'] === 'true') {
			continue;
		}

		// Hide the complete create entry group
		group.style.display = 'none';

		// Mark as processed to avoid duplicate work
		group.dataset['createEntryHidden'] = 'true';
	}
}

 

View solution in original post

2 Replies
SebastianKrings
Frequent Contributor

I found a way to access it, but since the Editor-Type is still deprecated I guess this is not a good long-term way.

Any suggestions here?

const editorElement = document.querySelector('arcgis-editor') as (HTMLElement & {
    componentOnReady?: () => Promise<void>;
    widget?: Editor;
}) | null;

if (!editorElement) {
    return;
}

if (typeof editorElement.componentOnReady === 'function') {
    await editorElement.componentOnReady();
}

const editorWidget = editorElement.widget;
if (!editorWidget?.viewModel?.featureTemplatesViewModel) {
    return;
}

editorWidget.viewModel.featureTemplatesViewModel.filterFunction = item => {
    return !excludedTitles.some(title => item?.label?.startsWith(title));
};

 

Edit: This Template Solution does not work, because, when creating one of these excluded Features via Relation of another non-excluded Feature, they are not selectable.

SebastianKrings_0-1779194735911.png

 

SebastianKrings_1-1779194744992.png

So the dirty DOM Solution is the one to choose.

As an dirty alternative we also found another (more future reliable way) by DOM manipulation:

/**
 * Observes the ArcGIS Editor shadow DOM for runtime UI updates.
 * The ArcGIS Editor dynamically rebuilds its internal DOM structure.
 * Therefore hidden create entries would reappear after rerendering
 * without a MutationObserver.
 * This observer listens for DOM changes and reapplies the
 * create-entry hiding logic whenever the editor updates itself.
 */
private observeEditorDom() {

	// Get the ArcGIS editor web component
	const editor = document.querySelector(
		'arcgis-editor'
	) as HTMLElement | null;

	// Abort if the shadow DOM is not available yet
	if (!editor?.shadowRoot) {
		return;
	}

	const root = editor.shadowRoot;

	// Reapply hiding logic whenever the editor rerenders
	const observer = new MutationObserver(() => {
		this.hideConfiguredCreateEntriesAsync(root);
	});

	// Observe the complete editor subtree for changes
	observer.observe(root, {
		childList: true,
		subtree: true
	});

	// Initial execution after observer registration
	this.hideConfiguredCreateEntriesAsync(root);
}

/**
 * Hides configured layer create entries from the ArcGIS Editor UI.
 * Important:
 * - Only the visible UI entries are hidden
 * - Layers/templates remain fully functional internally
 * - Related feature creation therefore still works
 * The method only targets the "Create Features" section.
 * Related feature dialogs are ignored automatically because they
 * use a different DOM structure.
 * @Param root Shadow root of the ArcGIS Editor component
 */
private async hideConfiguredCreateEntriesAsync(root: ShadowRoot) {

	// Get currently active flow item inside the editor
	const selectedFlowItem = root.querySelector(
		'calcite-flow-item[selected]'
	) as HTMLElement | null;

	// Only the Create Features Section contains this container.
	// Related feature dialogs do not contain it.
	const createTemplatesContainer = selectedFlowItem?.querySelector(
		'.esri-editor__feature-templates-container'
	);

	// Abort if current view is not the create-features screen
	if (!selectedFlowItem || !createTemplatesContainer) {
		return;
	}

	// Resolve layer names dynamically via schema configuration
	const hiddenEntryNames =
		...) ?? [];

	// Collect all create-entry groups rendered by ArcGIS
	const groups = Array.from(
		createTemplatesContainer.querySelectorAll(
			'.esri-item-list__group'
		)
	).filter(
		(element): element is HTMLElement =>
			element instanceof HTMLElement
	);

	// Iterate through all rendered create groups
	for (const group of groups) {

		// Extract the visible heading text
		const groupHeading = group.querySelector(
			'.esri-widget__heading'
		);

		const groupHeadingText = groupHeading
			?.textContent
			?.trim();

		// Skip invalid entries
		if (!groupHeadingText) {
			continue;
		}

		// Check whether current group should be hidden
		const shouldHide = hiddenEntryNames.some(
			hiddenName => groupHeadingText === hiddenName
		);

		// Skip unrelated or already hidden groups
		if (!shouldHide || group.dataset['createEntryHidden'] === 'true') {
			continue;
		}

		// Hide the complete create entry group
		group.style.display = 'none';

		// Mark as processed to avoid duplicate work
		group.dataset['createEntryHidden'] = 'true';
	}
}

 

SebastianKrings
Frequent Contributor

I not heard that another colleague had already contact to some Devs from ESRI and they are on it to add a top level option to achieve this. Til then we simply use the dirty workaround.

0 Kudos