How to remove a DOM Element with PureScript

by||2 min read

Recently I have written a small article on How to remove a DOM Element with JavaScript. So I was wondering what this code would look like in PureScript since it is type safe and more strict than plain JavaScript code. Let's find out together!

First of all, let's create our HTML file and a simple sample application by running

spago init
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>Tutorial</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" type="text/css" media="screen" href="main.css" />
  </head>
  <body>
    <div id="targetElement">This needs to go</div>
    <script src="main.js"></script>
  </body>
</html>

Your Main.purs file should look something like this:

module Main where

import Prelude

import Effect (Effect)
import Effect.Console (log)

main :: Effect Unit
main = do
  log "🍝"

We can not start to write our code to access and element by Id and remove it from the DOM (in my example it will be the div with the id #targetElement.

Obviously we can not just use window or document in PureScript. We need to access it in a monadic way inside en Effect:

import Web.HTML.HTMLDocument (toNonElementParentNode)
import Web.HTML.Window (document)
import Web.HTML (window)
import Web.DOM.NonElementParentNode (getElementById)

main :: Effect Unit
main = do
  doc <- map toNonElementParentNode $ document =<< window
  maybeElement <- getElementById "targetElement" doc

At this stage we will have the access to an Element (if it exists in the HTML DOM structure). If you are interested in understanding the logic behind getElementById, I advice you reading "How to getElementById in PureScript".

Now let's elaborate a bit on the remove function:

import Web.DOM.Node (Node, removeChild, parentNode)
import Web.HTML.HTMLElement (HTMLElement, toNode, fromElement)

removeHtmlElement :: HTMLElement -> Effect Unit
removeHtmlElement htmlElement = do
  maybeParent <- parentNode nodeToRemove
  for_ (maybeParent) $ \parent' -> do
    removeChild nodeToRemove parent'
  pure unit
  where
  nodeToRemove :: Node
  nodeToRemove = toNode htmlElement

We can use the Web.DOM.Node module to work with Nodes (for instance access a parentNode and remove a child from a given Node). As in the plain JavaScript example we will use the removeChild function.

I have created a new function which takes a HTMLElement, fetches its parent and calls removeChild with the child and the parent. For this, we transform the given HTMLElement to a Node to be able to work with parentNode and removeChild.

Let's glue everything together by using the for_ function from the Data.Foldable module:

module Main where

import Prelude

import Data.Foldable (for_)
import Effect (Effect)
import Effect.Console (log)
import Web.DOM.Node (Node, removeChild, parentNode)
import Web.HTML.HTMLElement (HTMLElement, toNode, fromElement)
import Web.HTML.HTMLDocument (toNonElementParentNode)
import Web.HTML.Window (document)
import Web.HTML (window)
import Web.DOM.NonElementParentNode (getElementById)

main :: Effect Unit
main = do
  log "🍝 Starting Sample Code"
  doc <- map toNonElementParentNode $ document =<< window
  maybeElement <- getElementById "targetElement" doc
  -- Only remove element if it is found in the DOM
  for_ (maybeElement) $ \element -> do
    -- Transform an Element to a HTMLElement
    for_ (fromElement element) $ \htmlElement -> do
      removeHtmlElement htmlElement
    pure unit

removeHtmlElement :: HTMLElement -> Effect Unit
removeHtmlElement htmlElement = do
  maybeParent <- parentNode nodeToRemove
  for_ (maybeParent) $ \parent' -> do
    removeChild nodeToRemove parent'
  pure unit
  where
  nodeToRemove :: Node
  nodeToRemove = toNode htmlElement

Et voila! Here you have it. If you execute the code in the browser with our HTML, the element with the id #targetElement should completely disappear from the DOM!

Thank you for reading this far! Let’s connect. You can @ me on Twitter (@debilofant) with comments, or feel free to follow. Please like/share this article so that it reaches others as well.

© Copyright 2022 - Ersocon - All rights reservedVer. 2.3.6.9