DEV Community

Melissa Guachun
Melissa Guachun

Posted on

Relearning the Past: Vanilla JavaScript Single Page Application

Since my introduction to this language during bootcamp, I've been stumped by the possibilities of vanilla Javascript. Among my class, everyone seemed to be divided into two groups. Half of my classmates were immediate lovers of javascript and the other half, including myself, were completely stumped. To me, JavaScript was the wild west of languages, where anything goes. You're able to construct actions in methods on a microscopic level, which to me seemed overwhelming.

To me, the feeling can be described to when I was freelancing as an artist. I was always eager to dive into a final draft of a commission. To some, the prospect of staring at a blank page, waiting to be drawn upon can be intimidating. But I found it exhilarating.

But in the same sense of staring at a blank computer screen, the feeling of exhilaration was replaced with confusion and uncertainty. I truly didn't know where to start and felt thwarted with guilt. I began doubting myself even more, what good am I if I can't even think like a software engineer?

When the time came to create my JavaScript project, it was like my nightmare had come true. If it wasn't for my temporary cohort teacher leading the JavaScript section and the support of my classmates, I would've probably spent all my project time crying.

Once finishing JavaScript, my bootcamp eagerly pushed us ahead to React.js where I found some much needed relief.

Since then, I've sorta felt haunted by my javascript inadequacies.

I didn't really know how to think like my javascript savvy peers. It felt as if they possessed a javascript gene that I innately lacked. Those feelings became heightened when I decided to pursue more frontend and full stack positions.

As painful as it was to admit, I knew that JavaScript was a necessary language for me to learn in order to be a better programmer.

I decided to relearn how to remake a single page application (SPA) using only vanilla javascript (no frameworks). I based this project off of my original javascript SPA project from my bootcamp. Single page applications are commonly used by individuals and even large companies, so I thought this would be a pretty cool and practical project to embark on.

Unlike my bootcamp SPA, I decided to make something similar to a personal site. I also decided to not make a backend, as I wanted to focus on more frontend qualities of vanilla javascript for now.

To make this project even more enjoyable, I decided to make the personal site around my dog Fletcher.

Starting off this project, I created the appropriate files. With no frameworks in use, the set up was very easy and minimal. The first thing I built out was the pages. I defined the object pages and gave it key value pairs. The keys would be the page names and the values would be the content of those pages.

var pages = {
        'home' :   `
        <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>
}
Enter fullscreen mode Exit fullscreen mode

Above is an example of what the page and its content looks like. I created other pages such as a page for contact, services, and about. Once I had my pages built out, I needed a function to get and display the page with the appropriate content.

I built out a function called getPageContent that takes in the parameter page. Page is the string that will define the content being shown depending on the name of the page. We use a switch statement with page as the parameter, and will be matched with our options of page names.

function getPageContent(page) {
        var contentToReturn;
        switch(page){
            case 'home': 
            contentToReturn = pages.home;
            break;
            case 'about': 
            contentToReturn = pages.about;
            break;
            case 'services': 
            contentToReturn = pages.services;
            break;
            case 'contact': 
            contentToReturn = pages.contact;
            break;
            default: 
            contentToReturn = pages.home;
            break;
        }
}

Enter fullscreen mode Exit fullscreen mode

If there is a match, we show the appropriate page by accessing the pages object and its key value. The last case line is in case a match isn't found, the page will return to the home page.

Before we end this function, we add a document method. We utilize this method to be able to quickly find the matching element object to be returned. The whole point of a single page application is that there is no reloading involved. So it's important that this feature works.

    function getPageContent(page) {
        var contentToReturn;
        switch(page){
            case 'home': 
            contentToReturn = pages.home;
            break;
            case 'about': 
            contentToReturn = pages.about;
            break;
            case 'services': 
            contentToReturn = pages.services;
            break;
            case 'contact': 
            contentToReturn = pages.contact;
            break;
            default: 
            contentToReturn = pages.home;
            break;
        }
        document.getElementById('content').innerHTML = contentToReturn
    }

Enter fullscreen mode Exit fullscreen mode

This method allows us to get the matching element and it's content. But right now, this method doesn't work until we define it in the html body.

<body onload="getPageContent('home');">
    <header class="header">
        <a href="./index.html" class="header_logo">Fletcher Flyer</a>
        <ul class="header_nav">
            <li class="header_list" style="line-height: 50px;"><a href="#" class="header_link" onclick="getPageContent('home')">Home</a></li>
</ul>
</header>
<div id="content"> </div>
</body>

Enter fullscreen mode Exit fullscreen mode

In the header we use a hyperlink tag, connecting one page to another. In this case, we are directing our code to be read from our index.html file. That is where all of our content lives.

On Load helps us execute a javascript script once a page has been loaded. We directed the home page to be the landing page for our app.

In an li tag, we build out our home root. Within it, we use the onclick event that will take the use to the appropriate page. This occurs because we are calling on the getPageContent method with the parameter as the string 'home'. This will match the key of home to its value which is the content of the home page.

I repeat routes the syntax for the rest of the pages. Once that was done, I was surprised how within a few lines of code I had the basic layout for my SPA. It gave me even more time to explore the design aspect of this project like utilizing javascript for responsiveness and css stylings. It reminded me how powerful JavaScript truly is.

Looking back at where I was mentally when I was first learning JavaScript, it probably wasn't the best.

JavaScript was the fourth language I was learning during my bootcamp and my brain was basically mush. The whole point of a coding bootcamp is to test your limits, study hard, and put in the work. But that can clutter your mind when you're going from one language to another.

It brings home the importance of focusing on one language once you graduate. For myself, I know that JavaScript is going to be part of my career because of the positions I am passionate about pursuing. So I know, if I want to be a better frontend engineer, I need to be a better javascript engineer.

Coming out of my bootcamp made me a bit jaded, thinking I could just hop from one language to another after learning the basics. The truth is, if you want to be grow after your bootcamp, it's the best policy to choose a language and devote your time to mastering it.

There are so many language fads that go in and out of demand in the job market that can sway you in your choice. It can be hard to shut that influence out. In the end, you have to think about what's best for you, and the path you want to take in this field.

Conclusion:
JavaScript is still a bit intimidating to me. Though, I understand the more I work at it, the less scary it will become. It's really all about putting in the time. This project proved that I can code in JavaScript and understand every line of code that I write.

It's also important to mention that when revisiting, relearning, or starting a new language, to not compare yourself to others. Everyone has their own learning curve. Methods and functions that I used in my bootcamp all of a sudden make sense to me now. Sometimes your mind just needs time to absorb what you've learned.

Also, to my fellow peers who have entered the tech field as a career switch, don't give up. I battle with myself, thinking that because of my art background, I'm unable to think like an engineer. That's just destructive talk. There is no such thing as "thinking like a software engineer". We come from different backgrounds and find ourselves in this incredible new field. We bring so much to the table, that if we all homogeneously thought "like a software engineer", the tech world would be obscenely boring. It all comes down to trying, and putting the time in to learn and grow.

If you wanna checkout my full project, you can find it on my GitHub.

Top comments (8)

Collapse
 
fullzero5 profile image
FullZero

Maybe you don't even need to use the switch

const pages = {
  'home' :   `
        <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>`,
   'about': ` <h1>About Page</h1><br>`,
   'contacts': ` <h1>ContactsPage</h1><br>`
}
const getPageContent = (page = 'home') => document.getElementById('content').innerHTML = pages[page]
document.addEventListener("DOMContentLoaded", () => getPageContent());
Enter fullscreen mode Exit fullscreen mode
Collapse
 
peerreynders profile image
peerreynders • Edited

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."

Collapse
 
melguachun profile image
Melissa Guachun

Thanks for pointing that out!!

Collapse
 
peerreynders profile image
peerreynders

JavaScript is still a bit intimidating to me.

I found that separating things can help.

For example:

MDN: Object.hasOwn()

Breadcrumbs:
References > JavaScript > JavaScript > Standard built-in objects > Object > Object.hasOwn()

MDN: Document.getElementById()

References > Web APIs > Document > Document.getElementById()

Object.hasOwn() is part of JavaScript while Document.getElementById() isn't. Both JavaScript and the Web APIs have their own quirks but knowing who is responsible for what can sometimes help.

With other programming languages there usually is a clearer separation between the standard library and the host specific APIs. Perhaps learning JavaScript and a framework at the same time can have the same disorienting effect because there is no clear distinction between the framework APIs and the standard built-ins.

The DOM is doing its own thing, can't blame JavaScript for that.

Collapse
 
melguachun profile image
Melissa Guachun

Thank you for this super informative and detailed walk-through!! I'll dive back into this project and make some changes!

Collapse
 
devfranpr profile image
DevFranPR

Love the Eric Andre gifs to add emphasis.