loading...

Refactoring as a Slow but Necessary Process

alexlsalt profile image Alex Morton ・Updated on ・3 min read

This post was originally published on August 28, 2020 on my blog.

I did it! I got my podcast episodes to render dynamically on the podcast page on my website.

Well, they're dynamically rendered via an object of pre-filled episode data in my JavaScript file instead of hard-coding a brand new Section element in my HTML file.

So, technically, I'm still hard-coding into the JS file, but... baby steps.

I had a total learning moment yesterday, though, when I discovered that you can't just insert a script into an 'insertAdjacentHTML' call in JS because by the time your script gets added, the page has already loaded - so, as I understood it, it's kind of like your script arrived at the station as the train had already left.

(Each script tag contained the the individual episode-player.)

To get around that, I had to create a script for each podcast-episode-section-HTML after the page was loaded and createElement('script') with and set the src of each as each individual epiosde's URL.

I also had to create a data-key attribute for each episode so that I could match up the episode to the corresponding element in the 'episodes' object that contains each episode's information.

That moment when everything came together, though - ugh! I live for that!!!

Here's the logic for rendering each episode (before adding the script tags to each episode):

function renderListItems(list) {
  let dataKey = 0;

  list.forEach(el => {

      let html = `<section class="episode" data-key=${dataKey}><h2 style="text-align: center;">${el.title}</h2> <div id="buzzsprout-player-${el.id}" class="podcast-player"></div> <span>${el.description}Music credit to <a href="https://soundcloud.com/thisislegang" rel="noopener" target="_blank">Le Gang</a></span></section>
      `;
      document.querySelector('#episode-list').insertAdjacentHTML('beforeend', html);

      dataKey++; 
  });  

}

So, once the page loads, all the HTML is rendered, and then the program runs back through and creates/adds the script tags containing the episode-player:

window.addEventListener('load', () => {

  // Render all podcast episodes
  renderListItems(episodes);

  // Add individual script tags for each podcast player
  const episodeHtml = document.querySelectorAll('.episode');
  episodeHtml.forEach(el => {

    let i = el.getAttribute('data-key');
    let script = document.createElement('script');

    script.src = episodes[i].url;

    el.appendChild(script);
  });
});

Next step here is to get the episodes to populate by making a call to the Buzzsprout API (Buzzsprout is the podcast hosting service I use). This is great, because I've been wanting to build more things with APIs, so I can add that in there!

That'll be on today's plate, as well as more practice in my React ebook, which I'm steadily working my way through. I'm building a clone of a file list in GitHub at the moment, so I'm going to take what I've done fully apart in order to rebuild it using the knowledge I've already gained.

I mentioned in a previous post that I'm focusing on moving through the material very slowly as a means to move more quickly over the long run.

I know, it doesn't make sense right when we first read that; but honestly, it's a game-changer. I keep telling myself that if I move on quickly and without fully understanding a concept, it's going to cost me much more time down the line to have to go back and re-learn it.

So I'm taking that extra time as I'm learning something to make sure it's 100% dialed in.

Happy Friday.


P.S. Did you know I have a podcast with new episodes each Wednesday? Go listen right over here >>

The Ladies Code Collective Podcast cover art

Discussion

pic
Editor guide
Collapse
eruizdechavez profile image
Erick Ruiz de Chavez

I am happy you were able to solve your problem, I love the feeling of finally figuring out a solution after spending a good chunk of time (and β˜•.. and 🧠) on it.

There is one thing I noticed on your first code snippet: dataKey.

You don't need to keep an additional counter with forEach, the second element on the callback is the index of the array or collection you are iterating (that is true for both, regular arrays and NodeLists). With a pretty small change, you can get rid of that small but real error prone variable.

function renderListItems(list) {
  list.forEach((el, dataKey) => {
    const html = `
      <section class="episode" data-key=${dataKey}>
        <h2 style="text-align: center;">
          ${el.title}
        </h2>
        <div id="buzzsprout-player-${el.id}" class="podcast-player" ></div>
        <span>
          ${el.description} Music credit to <a href="https://soundcloud.com/thisislegang" rel="noopener" target="_blank">Le Gang</a>
        </span>
      </section>`;

    document
      .querySelector("#episode-list")
      .insertAdjacentHTML("beforeend", html);
  });
}

Taking it one step further, instead of calling querySelector for every element of your list, you can cache that value:

function renderListItems(list) {
  const episodeList = document.querySelector("#episode-list");

  list.forEach((el, dataKey) => {
    const html = `
      <section class="episode" data-key=${dataKey}>
        <h2 style="text-align: center;">
          ${el.title}
        </h2>
        <div id="buzzsprout-player-${el.id}" class="podcast-player" ></div>
        <span>
          ${el.description} Music credit to <a href="https://soundcloud.com/thisislegang" rel="noopener" target="_blank">Le Gang</a>
        </span>
      </section>`;

    episodeList.insertAdjacentHTML("beforeend", html);
  });
}

And finally, since this code is doing the same for every element on the list, why not just gather all the strings into a single one and do a single call to insertAdjacentHTML?

function renderListItems(list) {
  const episodeList = document.querySelector("#episode-list");

  const html = list.reduce((aggregator, el, dataKey) => {
    return (
      aggregator +
      `
      <section class="episode" data-key=${dataKey}>
        <h2 style="text-align: center;">
          ${el.title}
        </h2>
        <div id="buzzsprout-player-${el.id}" class="podcast-player" ></div>
        <span>
          ${el.description} Music credit to <a href="https://soundcloud.com/thisislegang" rel="noopener" target="_blank">Le Gang</a>
        </span>
      </section>`
    );
  }, "");

  episodeList.insertAdjacentHTML("beforeend", html);
}
Collapse
alexlsalt profile image
Alex Morton Author

This is so great, Erick! Really appreciate you taking the time to share this. Can’t wait to dig in more once I get back to my computer! 😊