DEV Community

Discussion on: Relearning the Past: Vanilla JavaScript Single Page Application

Collapse
peerreynders profile image
peerreynders • Edited on

The switch is implemented with a default in case there is no matching page name, so…

const DEFAULT_PAGE = 'home';

function getPageContent(page) {
  const key = Object.hasOwn(pages, page) ? page : DEFAULT_PAGE;
  return pages[key];
}
Enter fullscreen mode Exit fullscreen mode

With template elements the HTML strings only have to be parsed once (and the templates could simply reside within the HTML).

(function () {
  const HOME_TEMPLATE = makeTemplate(
    `<div class="home">
     <h1>Welcome to the Fletcher Flyer </h1>
     <br>
     This is a blog by me, Fletcher the dog. <br>
     My mom thought it was about time I have my own site
     <br>to share my adventures and offer my services.
     <br>
     <br>
     Unlike the Disney hit show "Dog with a Blog", I cannot talk.
     <br>
     But I do have remarkable typing skills, soulful eyes,<br> and an eye for hats. 
     <br>
   </div>`
  );

  const ABOUT_TEMPLATE = makeTemplate(`<h1>About Page</h1><br>`);
  const CONTACTS_TEMPLATE = makeTemplate(`<h1>ContactsPage</h1><br>`);

  const DEFAULT_TEMPLATE = 'home';
  const templates = {
    home: HOME_TEMPLATE,
    about: ABOUT_TEMPLATE,
    contacts: CONTACTS_TEMPLATE,
  };

  function makeTemplate(htmlText) {
    const template = document.createElement('template');
    template.innerHTML = htmlText;
    return template;
  }

  function getTemplate(page) {
    const key = Object.hasOwn(templates, page) ? page : DEFAULT_TEMPLATE;
    return templates[key];
  }

  function loadPageContent() {
    const clone = getTemplate(DEFAULT_TEMPLATE).content.cloneNode(true);
    document.getElementById('content').replaceChildren(clone);
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', loadPageContent);
  } else {
    loadPageContent();
  }
})();
Enter fullscreen mode Exit fullscreen mode

Note that HTML inline event handlers will be blocked under a strict Content Security Policy (CSP).

They represent legacy DOM Level 0 event handling.

The historical counter arguments often miss that the environment a DOM level 0 event handler executes in can get extremely weird, leading to all sorts of surprising bugs.

For example:

<form>
  <button formmethod="get" onclick="console.log(disabled);debugger">click</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Clicking the button will log false in the console even though there is no such variable - only there is. Switching to the debugger it becomes clear that the handler executes within three nested with statements, one each for the document, form, and button practically polluting the handler's scope with the properties of each of those elements as variables; so disabled belongs to button.

For more details see: Unsafe Names for HTML Form Controls - Event Handler Scope

So the MDN's advice is:
"You should never use the HTML event handler attributes — those are outdated, and using them is bad practice."

Collapse
lexlohr profile image
Alex Lohr

That's still not necessary, as you can check if your page is in pages and otherwise return home (or a 404 page):

const getPageContent = (page) =>
  pages.hasOwnProperty(page)
  ? pages[page]
  : pages.home;
Enter fullscreen mode Exit fullscreen mode
Thread Thread
peerreynders profile image
peerreynders

FYI:
"Note: Object.hasOwn() is recommended over hasOwnProperty(), in browsers where it is supported."