Search code examples
javascripthtmlelectroncode-injection

Is it common practice to have a string that holds a large DIV and inject that into html using JS


Is it common practice to store a large div tree as a string in JS and insert it into the HTML using the .innerHTML variable when it's needed? For instance, I need to display a form when a user clicks a button. Currently, I have the HTML for the form saved as a string in a javascript file, and when the user clicks the button, this string is injected into the main HTML file. Is this how a problem like this would be approached or is there a better solution/algorithm? I am trying to make a native app using electron. I have to do similar operations repeatedly, and my JS file mainly contains strings. Is there a framework that combats this issue? Thanks!


Solution

  • Ok I am going to approach this from discussion point. Given:

    • Html code is held in string variable in JS file.
    • Intention is to show section of DOM on event trigger. (Iam using the term DOM loosely). Question:
    • Should this be done through css manipulation i.e. keeping the section hidden and then revealing it on event.
    • Should this be done with replace or inject content into section on trigger?

    Both approaches are valid. Web developer coming to the world of native development because are not used to the concept of something before DOM. All we have known is DOM and everything starts runs and ends with DOM.

    Electron packs chrome + nodejs into one environment through multi-process model. Which means your program in an Electron app starts off as a Node script and there is no DOM. Not even a thought of it.

    Suppose Node.js gets running and we use JS to run bunch of functions. then comes the time to use this magic class called a browser window. we fire it up which calls on chrome to create this classical browser window. just like opening a new tab on browser or another excel sheet or what ever; through browser window we are creating an entirely separate process that will load an HTML page. When there is an HTML there is JS and CSS; all this combined is DOM. What ever happens in DOM stays in DOM; node.js doesn't directly control it per say nor DOM controls node.js per say. they have to be called on actions as in when you would submit from trigger native browser functionality which obviously is maintained by electron environment as chrome is bundled into it. in another words we wont be running on internet for the sake of it. It is all happening locally. hence the words native pp development. It is bit of hijack per say.

    Anyways back to question JS or CSS....either ways its DOM related issue. that being said its no different how one would expect things to happen in conventional browser.

    CSS way

    <div id='container'>
    <div id='something' style='display:none;'>waited for button click to show</div>
    
    </div>
    

    Then on button click all you would have to do is change display: none; to display:block; you can even create toggle where display property changes on clicks etc.

    JS way

        <div id='container'></div>
    <script>
    var button = document.querySelector("#button");
    button.onclick = function(){
    document.querySelector("#container").innerHTML = "<div id='something' style='display:none;'>waited for button click to show</div>";};
    </script>
    

    Both ways are OK! BUT and there is BUT. if you do CSS way like normal browser functionality DOM already knows the element in question when it was painted. Whereas through JS way DOM doesn't know the element much after it was painted.
    This raises a problem any event that may be triggering from with in newly injected content through JS DOM doesn't know it because they have not been mapped into memory. So any customised clicks or what not will not work through JS way. They will through CSS way because all had been mapped on initial paint.

    SO you would either have to run bunch of event functions after the injecting to let DOM know what has changed and then tell it what to do. It wont recognise things on its own. OR you have to go the way of event delegation that is you capture all the events on container div then filter which one it is and do something accordingly. DOM would take care of the rest.

    for example:

    document.querySelector("#container").onclick = function(event) {
      let target = event.target; // where was the click?
    
      if (target.id != 'something') return; // not on something? Then we're not interested
    
      alert('found something'); // highlight it
    }; 
    

    FULL BLOWN examples CSS way

    document.querySelector("#something").onclick = function(){
    console.log('found');};
            
        document.querySelector("#button").onclick = function(){
        
        document.querySelector("#something").style.display = 'block';};
        
    <div id='container'>
    <div id='something' style='display:none;'>waited forevent<button id='button2' type="button">Alert Me!</button></div>
    <button id='button' type="button">Show Me!</button>
    
    </div>

    Now the JS way for it to work properly

    var htmlcode ="<div id='something' style='display:block;'>waited forevent<button id='button2' type='button'>Alert Me!</button></div>";
    
    
                
            document.querySelector("#button").onclick = function(){
            
            document.querySelector("#container").innerHTML =htmlcode;
            //you notice we are sort of delegating after the injection. if it was done the CSS way Js will throw error
            document.querySelector("#button2").onclick = function(){
        console.log('found');};
            };
            
        <div id='container'>
      <button id='button' type="button">Show Me!</button>
    
        </div>

    FULL event delegation

    document.querySelector("#container").onclick = function(event) {
      let target = event.target; // where was the click?
      if (target.id != 'button2') return; // not on anything other than inner button
    
     console.log('found'); // highlight it
    };
    
    // delegation happened even before content even existed or Dom knew about it. hence no error
    
    var htmlcode ="<div id='something' style='display:block;'>waited forevent<button id='button2' type='button'>Alert Me!</button></div>";
                   
                document.querySelector("#button").onclick = function(){
                
                document.querySelector("#container").innerHTML =htmlcode;
                //you notice no delegation here
             
                };
        <div id='container'>
          <button id='button' type="button">Show Me!</button>
    
            </div>

    Conclusion you are on right track and either ways is correct it all depends on scenario that is how frameworks do it. And the debate regarding keeping HTML and JS and CSS separate stems from the idea that if another developer is to read the code it should make obvious sense not need bunch of hours trying to figure out what is what and how. there is no harm mixing it up. I do it either way. However consideration have to be taken up when more than two people are involved in coding. When everything is bundled up in one place it can create a mess if some just changed something with out knowing context. Same can happen to if everything was coming from their own file. Secondly when you need to change something drastic separation of concern helps because you wont need to mess with core DOM document that is html. That is why SPA make note that main document is minimalist as possible rest comes from and gets injected from different files or codes not bundled into main code.

    So yes your right this is how its dealt in principal rest is all your particular scenario. Interactivity on elements within browser window is not node.js concern. what elements goes into browser window is node.js concern i.e. fetching html and js and putting it.

    If you need to populate that JS on many html pages then either make injection into browser window through node.js OR make a separate JS file that is called in to DOM through script tag or what ever and then make use of it. Again it all depends on scenario.