Many thanks for the suggestiom. I agree Floki is an incredibly powerful library but as the raw_html generated may not always be an EXACT copy, it may not be suitable.
Good suggestion regarding the seperation of HTML from JS. Will need to refactor later on.
Will love your thoughts on this
page_template.html.eex
<div>
<%= raw rendertem() %>
</div>
page_view.ex
defmodule TestWeb.PageView do
use TestWeb, :view
def rendertem do
{:ok, htmlfile} = File.read("lib/test_web/templates/page/template.html.eex")
String.replace(htmlfile, ["<div"], fn "<div" -> ~s("<div onclick="console.log\('Clicked'\);") end)
end
end
This problem is usually solved by having the template contain EEX code that does whatever behavior you’re looking for. Where is that file coming from that you’d need to transform it this way?
The file is an user uploaded HTML file (here its called template.html - which i admit is misleading) that is loaded as part of a main page and some interactivity (such as the js onclick event) must be dynamically loaded along with it.
So how is the above? Is there a better way? I tried EEx.eval_file instead of File.read but it was very slow.
So any insight on how one can replace the html tags to include an onclick event while rendering within a parent page? Thanks. And i agree its good practice to ensure it is sanitized prior.
When mutating HTML, definitely use something like Floki to get escaping and quoting right. For instance, both of the examples in this thread create broken HTML:
replaces <div with "<div ..." with extra double-quotes
Alternatively, consider alternative approaches:
generate the HTML with the needed attribute
bind a click event listener to the element dynamically; for instance, render the template inside a div and use that to attach a handler:
# in the HTML
<div class="template-content">
<%= render the template %>
</div>
# in the page JS
$(".template-content h2").click(...)
The rendered file’s contents will be seamlessly included - there’s no sandboxing / isolation, the bytes from the template will be presented as part of the parent page.
I am so grateful to you for such a well thought out and very reasonable reply.
What i am trying to actually is to append an alpinejs x-on:click attribute to specific html tags.
Besides the typo where h2 was supposed to read h1…
My concern is floki and other html libraries rewrite the html. My need is that all formatting must be preserved with just x-on attributes injected whereever required. And as x-on is being used, it obliviates the need for a seperate event listener.
Thank you and I hope i dont appear argumentative because i actually agree with all your suggestions. Just i am operating within constraints. Hope to hear your views.
However, if the template already contains Alpine-flavored markup it seems simplest to write the handlers directly there, instead of trying to insert them at runtime.
Sorry what do you mean by writing the handlers directly there?
Do you mean, editing the template prior to runtime?
I mean adding the handler when writing the template - if the template has Alpine code in it, presumably whatever / whoever is authoring it is OK writing Javascript.