1
\$\begingroup\$

I have many pieces of HTML code that are used in many parts of the website (controlled by javascript), like edit forms and dialogs. Instead of include-ing the html files using php, I made a system for storing these elements in a javascript variable array such that I can choose which files to include in each page and which files will be downloaded via ajax (and cached) only in the case they are needed.

Is this generally a good approach or should this kinda stuff be handled differently?

javascript file

var templates = [];

// convenience method for getting a copy of a template
async function copyTemplate(filename){
   return await getTemplate(filename, true);
}

// get a template from cache, or if not found download it via ajax
async function getTemplate(filename, returnClone = false){
   let template = templates[filename];
   if(template == undefined){
      template = templates[filename] = await getElementAjax('templates/' + filename);
   }
   return returnClone ? template.cloneNode(true) : template;
}

// called from code echoed by php to include some
// templates without additional http requests
function saveTemplate(template){
   const templateElem = template.content.firstElementChild;

   const buttons = templateElem.querySelectorAll('button');
   for(let i = 0; i < buttons.length; i++){
      preventAutoSubmit(buttons[i]);
   }
   templates[template.getAttribute('data-file')] = templateElem;
}

// gets an element from a file via ajax, I excluded the
// implementation of functions called by this function for brevity.
async function getElementAjax(url) {
   const response = await ajax(url, 'GET', null, 'document');
   const mainElem = response.getElementsByTagName('body')[0].firstElementChild;
   const buttons = mainElem.querySelectorAll('button');
   for(let i = 0; i < buttons.length; i++){
      preventAutoSubmit(buttons[i]);
   }
   return mainElem;
}

php file

function includeTemplates(){
   $args = func_get_args();
   foreach($args as $url){
      $code = file_get_contents('templates/' . $url);
      echo "<template data-file='$url'>$code</template>";
   }
?>
<script>
   {
      const templates = document.getElementsByTagName('template');
      for(let i = templates.length - 1; i >= 0; i--){
         if(templates[i].hasAttribute('data-file')){
            saveTemplate(templates[i]);
            templates[i].remove();
         }
      }
   }
   document.currentScript.remove();
</script>
<?php
}

Usage example

<?php includeTemplates('logs/logEntry.html',
                       'logs/logEntryEditForm.html',
                       'foo/bar.html'
                      ); ?>
<script>
   async function populateLog(){
      const logEntries = await getLogEntries();
      const logContainer = document.getElementById('logContainer');

      for(entry of logEntries){
         const entryElem = await copyTemplate('logs/logEntry.html');
         //
         // ... set textContent and other properties for elements in entryElem ...
         //
         logContainer.appendChild(entryElem);
      }
   }
</script>
\$\endgroup\$
  • \$\begingroup\$ So instead of building a webpage on the server, and retrieving it with one call, which is totally possible for the example you give, you use the client's browser to build the page using many calls? I struggle to find a use case for this. I guess that in certain situations it could reduce the amount of bytes transmitted, needed to build a page, but that would be the exception. I also wonder how this would affect the user experience on a slower device. \$\endgroup\$ – KIKO Software Aug 7 '19 at 6:38
  • \$\begingroup\$ @KIKOSoftware in this example it enables loading the rest of the page without having to wait for the time consuming part (getLogEntries()) which is loaded via ajax. The template retrieved with copyTemplate(...) in this example is downloaded together with the first http request (see the php function includeTemplates(...) which is called above the script element to echo the templates and add them to the templates cache) \$\endgroup\$ – potato Aug 7 '19 at 10:05
  • \$\begingroup\$ Also it does end up reducing the amount of bytes transmitted, having hundreds of log entries would mean sending a copy of the template hundreds of times from the server instead of just once. \$\endgroup\$ – potato Aug 7 '19 at 10:12
  • \$\begingroup\$ I get the second advantage, which I also mentioned, but the first one is debatable. You say that getLogEntries() is slow, and I believe you, but you still use it, so the page will still be slow at showing relevant information. If this function is slow it would be better not to retrieve all log entries, but just show a few, and only when the user scrolls down, or selects to see more entries, you load more. \$\endgroup\$ – KIKO Software Aug 7 '19 at 10:17
  • \$\begingroup\$ You're right @KIKOSoftware , I can load a part of it quickly and then load the rest with ajax. But this slow part is not what my templates system is responsible for, so far I understand that the templates are useful for reducing data transmission as you said, but other than that it's not really different from just echoing the code normally, just saves a few lines of code here and there for echoing and accessing these templates. \$\endgroup\$ – potato Aug 7 '19 at 10:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.