Eliom: how to set arbitrary attributes? / reference js modules?

Is there a way to set arbitrary attribute values for elements on a page?

More specifically, I want to set the “type” attribute on a < script > tag (created with either Html.F.script or Html.D.script) to “module” (type=module) so that I can reference 3rd party js libraries (not from any opam package) that I use in my own hand written js file that I would like to include in an eliom project. Without that I get errors at runtime in browsers complaining about functions cannot be exported except from modules. If there is a better way to accomplish referencing 3rd party js libraries (not from any opam package), please let me know too.

Regardless, I have looked and not found a way to set arbitrary attributes on elements, let alone script tags. I thought I had found it in tyxml in the string_attrib ~aname function but I could never get that to compile when I provide it with values.

Any help with either problem (referncing 3rd party js libraries or setting arbitrary attributes) would be appreciated. Thank you.

1 Like

Regardless, I have looked and not found a way to set arbitrary attributes on elements, let alone script tags. I thought I had found it in tyxml in the string_attrib ~aname function but I could never get that to compile when I provide it with values.

Are you talking about Eliom_content.Html.F.Unsafe.string_attrib? That one allows you to add a custom attribute to an Eliom HTML node. How does your compilation fail?

Also, consider opening a TyXML issue (or even better PR) about the missing type attribute for scripts :).

That worked. Thank you so much and for the quick response.

In retrospect my real question should have been: where can I find the string_attrib function? I knew it existed in tyxml. I found it scouring mli files looking for something that sets attributes. And therefore it should exist someplace in eliom. I also suspected it existed since I doubted the authors would leave out such an important function for setting attributes not already bound in tyxml.

I did not know the function resided under F.Unsafe. I still don’t really understand why it does reside under F.Unsafe. And I think I see multiple functions with similar names across some eliom source files. Why more than one? Why are those not the function I needed? I was guessing it might be available to me under F.Xml, but that was certainly wrong. I find the implementation difficult to understand and I realize I need to devote some time to studying it, but I wish there were some way to see all functions available to me for writing an eliom project, organized by the parent module, without having to peer into the implementation and functors, etc.

I see it now: http://ocsigen.org/tyxml/4.1.0/api/Html_sigs.T.Unsafe But I never got there while searching. I think I did look at http://ocsigen.org/tyxml/4.1.0/api/Html_sigs.T but did not notice the Unsafe module at the very bottom of a very large page. Nor would I have known to look at Unsafe. I’m surprised this attribute requires use of an “Unsafe” module. I will open a ticket when I get chance. Referencing 3rd party javascript modules would seem to be a rather basic necessity that should not require using the “Unsafe” module to set this attribute as though I were going off the reservation.

1 Like

Excellent points. But it’s complicated :).

To begin with, all the content-building functionality in Eliom is implemented with the Tyxml functors. This allows us to build many related and generally compatible (but not identical) Html and Svg modules; for client- and server-side code, reactive (R) or not, with functional and DOM semantics (F and D respectively), etc. This leads to a complex module structure, but it also puts a burden on document generation; ocamldoc is way less sophisticated than the OCaml module system and doesn’t properly “inline” functor invocations giving you the hierarchy that you would like. Such problems are possibly solved by odoc (which I am not familiar with), but in any case we would need a non-trivial transition.

With regards to Unsafe, well, this name has to be interpreted in the context of the guarantees provided by Tyxml. If you use the non-Unsafe functions, the result will be valid HTML because the types encode HTML validity rules (modulo some difficult to encode properties, e.g., when nesting is involved). In my experience we rarely ever need Unsafe; but of course I understand that it is possible to fall on an omission that happens to be critical for an application (type in your case). The normal course of action is to add the missing attribute/tag to TyXML. Clearly, we also need to clarify what Unsafe means and make it more discoverable (for when everything else fails).

Thank you so much for the explanation.

It turns out that I am very much inexperienced with JavaScript and Js_of_ocaml…so much so that I did not need the module attribute and I didn’t even know it. While I could set the attribute, it turns out that I could not get the JavaScript 3rd party functions to work with some JavaScript I had written – I had prematurely thought I had conquered the problem. I still would like to see if it possible to get that approach to work.

I did not realize that Js_of_ocaml has another way of allowing us to reference JavaScript file dependencies detailed here (under the heading “Provide your own JavaScript”): https://ocsigen.org/js_of_ocaml/3.1.0/manual/linker

I had never before seen that and so I had to annotate 3rd party JavaScript and my own JavaScript with //Provides: and //Requires: as detailed in the link. Going with that approach everything worked after a few attempts to determine what was needed. It is a little concerning that I often see warnings about free variables, etc., and I’m not sure what to do about them, and including them within Provides or Requires annotations doesn’t always solve the problem. And I can get my JavaScript to work despite the warnings, so I have hit upon some combination of annotations that works.

I’m not certain using modules and exported functions is even possible in the context of an Eliom project. Perhaps I will try that route again later.