What are "good" web-components for ELM?

I tried to use the ui5 webcomponents together with elm, to achieve a better look of my app. While buttons work as expected, the input-fields are throwing some errors, after removed form the screen. How can I check, whether a web-component will work together with elm or not, before implementing test-code?

Do you have any suggestions for a similar library? Support for localization (e.g. input of dates) and mobile devices is on the wish list.

1 Like

What are the errors? I could maybe help there.

You could use GitHub - matheus23/elm-tailwind-modules: Generate Elm code for Tailwind Utilities and Components that purges using Elm's --optimize! possibly.

1 Like

The thing about using web components and elm is to understand the web component cannot modify th dom outside itself and that Elm must be the single source of all state (including the state of the DOM).

So consider the case where you are throwing errors when an input field is being removed from the screen, was the disappearance of the input field something that happened through Elm? Is Elm aware that the dom changed? I don’t know if this makes sense but if your web components is affecting the dom tree outside of itself (including making itself disappear) then there will be a disparity between the new DOM and the virtual Dom that elm is using and this is the source of errors like this.

What you want to do is consider that all state including the state of the DOM need to go through Elm, it’s tricky at first and I ran into these same issues when I started using web components. I also found it helpful to make sure that anything that input needs from elm is passed to the component via attributes and that the component can dispatch any changes to elm via events. Also components must be leaf components that do one small discrete thing.

I found creating my own custom element and having it interact with elm went a long way towards understanding how web components and elm can coexist. It’s a lot of work up front but once you manage it I think it’s worth it and I find web components quite useful.

2 Likes

Thanks for offering help. Today I tmade a simple example, but this works as expected. I removed the code from the big app, so I have not keep the detailed error-message. I will try with the complete app tomorrow.

2 Likes

For some general information on usage of WebComponents with Elm, I’ll leave a link to A Guide to Using Elm With WebComponents here.

1 Like

This is the exception occurring hundreds of times:

Uncaught TypeError: Node.removeChild: Argument 1 is not an object.
    _VirtualDom_applyPatch https://[...]/index.js:12616
    _VirtualDom_applyPatchesHelp https://[...]/index.js:12574
    _VirtualDom_applyPatches https://[...]/index.js:12565
    _Browser_document https://[...]/index.js:12854
    updateIfNeeded https://[...]/index.js:12889

And this is the code, the exception occurs in case 6::

// APPLY PATCHES



function _VirtualDom_applyPatches(rootDomNode, oldVirtualNode, patches, eventNode)
{
	if (patches.length === 0)
	{
		return rootDomNode;
	}

	_VirtualDom_addDomNodes(rootDomNode, oldVirtualNode, patches, eventNode);
	return _VirtualDom_applyPatchesHelp(rootDomNode, patches);
}

function _VirtualDom_applyPatchesHelp(rootDomNode, patches)
{
	for (var i = 0; i < patches.length; i++)
	{
		var patch = patches[i];
		var localDomNode = patch.t
		var newNode = _VirtualDom_applyPatch(localDomNode, patch);
		if (localDomNode === rootDomNode)
		{
			rootDomNode = newNode;
		}
	}
	return rootDomNode;
}

function _VirtualDom_applyPatch(domNode, patch)
{
	switch (patch.$)
	{
		case 0:
			return _VirtualDom_applyPatchRedraw(domNode, patch.s, patch.u);

		case 4:
			_VirtualDom_applyFacts(domNode, patch.u, patch.s);
			return domNode;

		case 3:
			domNode.replaceData(0, domNode.length, patch.s);
			return domNode;

		case 1:
			return _VirtualDom_applyPatchesHelp(domNode, patch.s);

		case 2:
			if (domNode.elm_event_node_ref)
			{
				domNode.elm_event_node_ref.j = patch.s;
			}
			else
			{
				domNode.elm_event_node_ref = { j: patch.s, p: patch.u };
			}
			return domNode;

		case 6:
			var data = patch.s;
			for (var i = 0; i < data.i; i++)
			{
				domNode.removeChild(domNode.childNodes[data.v]);
			}
			return domNode;

		case 7:
			var data = patch.s;
			var kids = data.e;
			var i = data.v;
			var theEnd = domNode.childNodes[i];
			for (; i < kids.length; i++)
			{
				domNode.insertBefore(_VirtualDom_render(kids[i], patch.u), theEnd);
			}
			return domNode;

		case 9:
			var data = patch.s;
			if (!data)
			{
				domNode.parentNode.removeChild(domNode);
				return domNode;
			}
			var entry = data.A;
			if (typeof entry.r !== 'undefined')
			{
				domNode.parentNode.removeChild(domNode);
			}
			entry.s = _VirtualDom_applyPatchesHelp(domNode, data.w);
			return domNode;

		case 8:
			return _VirtualDom_applyPatchReorder(domNode, patch);

		case 5:
			return patch.s(domNode);

		default:
			_Debug_crash(10); // 'Ran into an unknown patch!'
	}
}

Looks like the web component you’re using is modifying the dom that elm is in charge of.

Yes! When leaving the focus of the ui5 input, a tag <ui5-static-area> is added after <body>.
While Browser.Sandbox works, Program raises the error.

Ok, this makes a lot more sense. Both Browser.document and Browser.application take over the entire <body /> of the page. Depending on what you’re building, you could use Browser.element if that works for you, or you could find 1 of the approaches for modifying the compiled Elm so that it doesn’t take over the whole <body />. Or maybe figure out why that <ui5-static-area> is being added and try to have it not be added. There are a few paths to pursue!

Seems the static area is lazy loaded to allow popups. Maybe I need to use Browser.element and update the URL using ports. :thinking:

1 Like

Yep! Either use Browser.element, or once your app grows and you decide you need Browser.document or Browser.application then you can run a script to modify the Elm output to not take over the whole <body />. But it’s probably best to start with Browser.element.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.