Script event order using Util.HtmlHead.AddScript
Hi,
I'm trying to run a script on DOMContentLoaded where I reference a DOM element in the body. My (incorrect) assumption was that the script would not be run until something is Dumped, but this isn't the case.
When doSomeProcessing
below runs, the console in devtools shows an uncaught TypeError on the originalParagraph.appendChild(s);
line, as originalParagraph
is null - it's not been loaded at this stage.
Is there a better event to listen to so that the I can know that the main content (via Util.RawHtml) has been added?
Best regards
John
void Main() { var sc = new SpecialControl(); sc.Dump(); } public class SpecialControl { const string js = """ if(document.readyState !== 'loading') { doSomeProcessing(); } else { document.addEventListener('DOMContentLoaded', function () { doSomeProcessing() }); } function doSomeProcessing() { let originalParagraph = document.querySelector("#firstMsg"); let s = document.createElement("span"); s.textContent = " DOM fully loaded and parsed"; originalParagraph.appendChild(s); let p = document.createElement("p"); p.textContent = "Other processing happening here"; document.body.appendChild(p); }; """; object ToDump() { Util.HtmlHead.AddScript(js); return Util.RawHtml($"<p id=\"firstMsg\">Initial message</p>"); } }
Comments
Have just discovered
Util.InvokeScript
and that allows me to remove the event listener and use the Util method to call the script.To wrap this in a ToDump method I'm calling .Dump() inside it, which feels a bit clumsy, but I can't see an obvious way of ensure the the expected html is going to be present, prior to calling the js function, without it. I also notice that there's a div of id 'final' that other dump output looks like it gets appended to.
Is there an option for some kind of
Util.HtmlBody.AddRawHtml
method that would add markup at the moment of calling in a similar way toUtil.HtmlHead.AddScript
?[Just fyi and background, my use case here is to output a table row of characters, measure the table columns (hence needing access) and then add a series of svg markers to identify various run types and their indices. My hope is to dump out as a standalone table and or as an object in the standard LINQPad object tables.]
It sounds like you need an OnLoad function on an arbitrary DOM element, which JavaScript doesn't support. You could try the hack documented here: https://stackoverflow.com/a/41685045
Here's a simple example using LINQPad's controls. MyControl is a composite element that contains two controls - the target that you want to manipulate with JavaScript, and an Image control whose onerror function will act as a load trigger for the target:
That's great. Thanks very much Joe. I don't think I've looked at Controls enough. I've read the Controls tutorials section, but have you done any talks/videos on their implementation? Would love to watch / listening to the thinking behind them if that exists.
Anyway, thank you again. This solves my issue and in a cleaner way than I was attempting.
Best regards
John