LogoLogo
  • FAC Curriculum
  • archive
    • Node & npm introduction
    • developer
      • Programming Paradigms
    • handbook
      • Asking for help
      • Coaching groups
      • Code review
      • Course rules
      • Debugging
      • Employment schedule and material delivered in FAC20
      • GitHub Workflow
      • Glossary or terms
      • Presentation Guidance
      • Equality, Diversity and Inclusion
      • Installation guide
      • Learning circles
      • Mentoring guidance
      • What to expect from your mentors
      • One-day projects
      • Pair programming
      • Portfolio
      • Questions for problem solving
      • Progress Logs
      • Final project report
      • Managing software projects
      • Project Presentations
      • Project roles
      • Projects
      • Retrospectives
      • Role Circles
      • Safeguarding policy
      • Technical Spikes
      • System requirements
      • Tech for Better
      • User Manuals
      • Wellbeing Support
      • project-docs
        • What makes a mentor?
        • Product Handover
        • Sprint Planning
        • Tech for Better Presentations
        • User Research & Usability Testing
    • foundation
      • full-stack
        • Learning Outcomes
        • project
      • testing
        • project
        • spikes
  • docs
    • Contributing to the curriculum
    • Curriculum intent
    • Curriculum process
  • src
    • About our curriculum
    • course
      • Code of Conduct
      • Docker
      • .NET and Umbraco
      • Getting started
      • Founders and Coders coursebook
      • KSB's
      • Mini projects
      • Revision checklist
      • Svelte
      • TypeScript
      • handbook
        • Software Developer Handbook
        • Software Foundation Handbook
      • precourse
        • Before you start the course
        • Installation List
      • syllabus
        • developer
          • app
            • learning-outcomes
            • project
            • schedule
            • spikes
          • introduction
            • learning-outcomes
            • project
            • resources
            • schedule
          • week00-pre-course
            • We'd like you to spend some time before starting the course working on useful fundamentals.
            • spikes
          • week01-project01-basics
            • Employability introduction
            • Homework
            • learning-outcomes
            • Week of September 9th
            • project
            • resources
            • schedule
            • spikes
          • week02-project02-chatbot
            • employability
            • Homework
            • learning-outcomes
            • Week of September 16th
            • project
            • resources
            • schedule
            • spikes
          • week03-project03-server
            • Learning Outcomes
            • Week of September 23th
            • The Amazin' Quizzer API Backend
            • resources
            • schedule
          • week04-project03-frontend
            • learning-outcomes
            • Week of September 30th
            • UI for Quizzer App
            • resources
            • schedule
          • week05-project03-test-deploy
            • Testing and deployment
            • Week of October 7th
            • project
            • resources
            • schedule
          • week06-project04-databases
            • learning-outcomes
            • Week of October 14th
            • project
            • Databases
            • schedule
          • week07-project04-authentication
            • Learning Outcomes
            • Week of October 21st
            • project
            • resources
            • schedule
          • week08-project04-test-deploy
            • Learning Outcomes
            • Week of October 28th
            • project
            • resources
            • schedule
          • week09-reading-week
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
          • week10-project05-DOTNET-intro
            • Learning Outcomes
            • overview
            • project
            • Resources
            • schedule
          • week11-project05-DOTNET-testing
            • Testing and deployment
            • Week of November 18th
            • project
            • Resources
            • schedule
          • week12-project05-DOTNET-deploy
            • Learning Outcomes
            • Week of November 25th
            • project
            • Resources
            • schedule
            • Spikes
          • week13-TFB-design
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
            • Design Week Spikes
          • week14-TFB-build
            • Learning Outcomes
            • overview
            • Project
            • DevOps Resources
            • schedule
            • Spikes
          • week15-TFB-build
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
            • Spikes
          • projects
            • in-house-design
              • Learning Outcomes
              • Project
              • Resources
              • schedule
              • Design Week Spikes
        • foundation
          • Obsolete-full-stack
            • project
          • post-course
            • Homework
            • schedule
        • portfolio
          • fruit-shop
            • learning-outcomes
            • project
            • resources
          • game
            • learning-outcomes
            • project
            • resources
          • hobby-page
            • learning-outcomes
            • project
            • resources
          • movie-data
            • learning-outcomes
            • project
            • resources
          • project-gallery
            • learning-outcomes
            • project
            • resources
          • website
            • learning-outcomes
            • project
            • JavaScript
        • tfb
          • week 1
            • Introduction (45 minutes)
            • Further reading
          • week 10
            • content
            • resources
          • week 11
            • What will we be doing this week?
            • resources
          • week 12
            • What will we be doing this week?
            • Further reading
          • week 2
            • Discover (90 minutes)
            • resources
          • week 3
            • content
            • resources
          • week 4
            • Mapping the user journey (90 minutes)
            • resources
          • week 5
            • Figma Workshop 1 (90 minutes)
            • Further reading
          • week 6
            • Figma Workshop 2 (90 minutes)
            • resources
          • week 7
            • Product pitches & Selection (90 minutes)
            • resources
          • week 8
            • content
            • resources
          • week 9
            • content
            • resources
    • learn
      • DOTNET
        • Introduction to .NET
      • auth
        • Authenticating web apps
      • database
        • Persisting data with SQLite and Node
      • dotnet-two
        • Dependency injections and interfaces in .NET
      • form-validation
        • Form validation
      • react
        • Building client-side apps with React
      • server
        • HTTP servers with Node & Express
      • typescript
        • TypeScript
    • mentoring
      • design-week
        • Analysis Workshop
        • Code planning
        • Definition Workshop
        • Discovery Workshop
        • Figma introduction
        • Usability testing
        • User Research
    • resources
      • http
        • introduction
    • workshops
      • cookie-auth
        • index
      • creating-promises
        • index
      • css-layout
        • index
      • cypress-testing
        • index
      • database-testing
        • index
      • dev-tooling
        • Developer tooling
      • dom-challenge
        • index
      • dom-rendering
        • index
      • es-modules
        • index
      • express-middleware
        • Express middleware
      • first-class-functions
        • index
      • form-validation
        • index
      • functions-callbacks-async
        • Functions, callbacks, & async JavaScript
      • git-intro
        • Introduction to Git
      • git-terminal
        • Using Git in the terminal
      • git-workflow
        • Git workflow
      • github-projects
        • GitHub Projects Workflow Workshop
      • heroku-sql-challenge
        • index
      • html-forms
        • index
      • learn-a11y
        • index
        • starter-files
          • solution
            • Accessibility solution explanation
      • learn-fetch
        • index
      • learn-integration-testing
        • index
      • learn-testing
        • Learn testing in JavaScript
      • learn-unit-testing
        • index
      • node-error-handling
        • Node error-handling
      • node-express-server
        • Node and Express HTTP server
      • node-npm-intro
        • Node & npm introduction
      • node-postgres
        • Learn Postgres with Node
      • node-scripting-challenge
        • index
      • password-security
        • index
      • promise-practice
        • index
      • react-components
        • React components
      • react-fetch
        • index
      • react-forms
        • React forms
      • react-refactor-classes
        • index
      • react-state-effects
        • React state & effects
      • real-world-fetch
        • index
      • scope-challenge
        • Scope debugging challenge
      • semantic-html
        • index
      • server-side-forms
        • Server-side forms
      • session-auth
        • Session authentication
      • sql-intro
        • index
      • tdd-array-methods
        • index
Powered by GitBook
On this page
  • Setup
  • document.createElement
  • Appending nodes
  • Challenge 1
  • Abstracting createElement
  • Challenge 2
  • innerHTML
  • Challenge 3
  • Stretch goal: the <template> element
  • Challenge 4
  • Defining templates in JS
  • Conclusion
Export as PDF
  1. src
  2. workshops
  3. dom-rendering

index

Practice rendering DOM elements using three different techniques.

Setup

  1. Download starter files

  2. Run npx servor workshop to start a dev server

We'll be using three different methods to render the same dynamic UI to compare them. The UI will include a static single element (the title), plus a list of dynamic elements rendered from an array.

There is an array of dog objects in workshop/dogs.js. In each challenge you'll need to import that data and render the following UI:

<h1>All the dogs</h1>
<ul>
  <li class="card">
    <h2>Dog name</h2>
    <img src="dog image url" alt="" />
  </li>
</ul>

with a list item for each dog in the array.

The HTML document contains a single container to render all the UI into: <div id="app"></div>.

document.createElement

The standard way to create new DOM elements in JavaScript is the document.createElement method. You pass in a string for the HTML element you want to create and it returns the new DOM node. You can then manipulate the node to add attributes and content.

Appending nodes

Once you've created DOM nodes you have to append them to their parent (and eventually to a node that is actually on the page). The classic way to do this is element.appendChild(newNode). This puts newNode inside the element node. If element is already on the page then newNode is rendered.

This has a big drawback: you can only append one thing at a time. This can lead to inefficient rendering. Each time you append a new element to the page the browser has to re-render everything. It's better to get all your DOM nodes ready then append them to the page in one go.

container.append("Some text", newNode, anotherNode, "more text");

This is powerful when combined with the spread operator, as it means you can append an array of elements in one go:

const elements = dogs.map((dog) => createListElementSomehow(dog));
container.append(...elements);

Challenge 1

  1. Open app.js and import the dogs array

  2. Use document.createElement and append to render:

    • a page title

    • an unordered list

    • a list item for every dog in the array

  3. Put all these elements inside the <div id="app"> in the HTML

Abstracting createElement

We can write our own function to make it simpler to create DOM elements. Ideally we'll be able to pass in a tag name, some properties and some children, and have all the document.createElement stuff handled automatically. E.g.:

const p = createEl("p", { id: "test" }, "Some text content");
// <p id="test">Some text content</p>

We'll create this in a new file create-element.js, so we can re-use it in multiple places if we need to.

function createEl(tag, props, ...children) {
  // ...
}

First we need to create a new element using the tag argument:

function createEl(tag, props, ...children) {
  const element = document.createElement(tag);
}

then we need to append all the properties from the props object onto the DOM element:

function createEl(tag, props, ...children) {
  const element = document.createElement(tag);
  for (const prop in props) {
    element[prop] = props[prop]; // e.g. element.id = "test"
  }
}

Finally we need to append all the children to the new element. We already saw how append combines with the spread operator to add a whole array of children at once:

function createEl(tag, props, ...children) {
  const element = document.createElement(tag);
  for (const prop in props) {
    element[prop] = props[prop];
  }
  element.append(...children);
  return element;
}

Don't forget to return the new element! We now have a nice helper function that we can export to use in our other file.

Challenge 2

Use your new createEl function to refactor your previous solution. Does it simplify the code?

innerHTML

This method almost feels like cheating. If you set an element's innerHTML property to a string the browser will render it. This makes it a quick way to render a chunk of DOM, especially combined with template literals:

container.innerHTML = `<div>Hello ${name}</div>`;

There are a couple of downsides to this method. First innerHTML is considered a security risk. If you ever insert user input into an HTML string (like above) you run the risk of XSS attacks (cross-site scripting). A user could insert <script src="steal-credit-cards.js"></script> as the name variable, and your code would render that to the page, causing it to immediately execute.

It can also potentially be slow, since every time you change a node's innerHTML property the browser must completely scrap and recreate its entire DOM tree. If you (for example) keep appending to innerHTML in a loop you'll cause a lot of unnecessary re-renders. Nowadays browsers are so fast this is less of a concern.

Challenge 3

Use innerHTML and template literals to create the same UI as before.

Stretch goal: the <template> element

The template element is a special HTML element designed for rendering dynamic UI with JavaScript. The template (and all its contents) don't appear on the page. It's like a reusable stamp: you have to use JS to make a copy of the template, fill in the blanks, then append the copy to the page.

<!-- index.html -->
<template id="homeTemplate">
  <h1 class="title"></h1>
</template>
const template = document.querySelector("#homeTemplate");
const clone = template.content.cloneNode(true);
const title = clone.querySelector("h1");
title.textContent = "Hello world";
container.append(clone);

This is useful because we don't have to dynamically create elements: we can use the ones already created inside the template.

Challenge 4

Use the template element to create the same UI. You'll need to edit the HTML file too.

Defining templates in JS

It's a little annoying that templates have to be defined in the HTML file. We're doing all our rendering within JavaScript, so it would be nice to keep all the templates there too.

We can work around this by combining all three of our rendering methods. We can create a new template element within our JS, set its content using innerHTML, then clone that template whenever we need a copy. The template is never actually on the page, it just lives inside our JS.

const template = document.createElement("template");
template.innerHTML = `<h1 class="title"></h1>`;
// clone the template same as before

This also avoid the problems with innerHTML, since we won't be passing user input into it. Our only use of innerHTML will be the initial static markup.

Challenge 5

Remove your template elements from the HTML file and instead create them with JavaScript. Refactor your previous solution to use this technique.

Conclusion

All of these techniques are valid, and all have their place. It's good to understand the platform you're working with, even if you end up using a framework like React that handles lower-level DOM manipulation for you.

Previousdom-renderingNextes-modules

Last updated 4 years ago

There's a newer method with a nicer API: . This is supported by all browsers but IE11. It can take as many elements to append as you like, and it even supports strings to set text content.

The ... is the —it gathers any additional arguments into an array. Any arguments after the props object will go into a single array named children.

element.append
rest operator