dcsimg
 

Replace HTML Elements using jQuery

Thursday Apr 22nd 2021 by Rob Gravelle

This web development tutorial shows you how to replace HTML links in spans using a versatile jQuery function.

A few years back, I wrote a tutorial on Filtering IFrame Content using jQuery. In that instance, interactive content from the same site was being presented in a static format. More recently, I had to undertake a similar task that involved filtering out links from third-party content. Once again, jQuery was a huge help in making what could have been a challenging exercise a much easier one. In this tutorial, we'll write a versatile function for replacing links with spans.

The Problems with Links in External Content

By including links from external sites in your web apps or pages, you may be opening yourself up to a variety of issues and threats, an obvious one being scripting attacks. Another, perhaps less obvious, problem is that most sites use relative links in their pages. Once you serve that content from your site, links will now point to your server, where you'll get a 404 error. The following screenshot shows external content in our application, including active links in blue:

Replace Links with Span jQuery HTML

Introducing the linksToSpans() Function

We decided to convert link "(<a></a>)" tags to spans ("<span></span>") so that we could still apply some styling to link elements to differentiate them from the rest of the text. In my case, the conversion was accomplished using an Angular pipe that processed the HTML content; for the purposes of this tutorial, I incorporated the conversion code into a function that can accommodate HTMLElements and raw HTML in addition to jQuery objects. Here is the linksToSpans() function in its entirety (we'll break it down afterwards):

function linksToSpans(targetElt) {
  var targetIsString = typeof targetElt === 'string';
  if (targetIsString) {
    targetElt = $('<div></div>').html(htmlContent);
  } else if (targetElt instanceof HTMLElement)  {
    targetElt = $(targetElt);
  } else if (!(targetElt instanceof jQuery)) {
    throw 'Invalid Target Element type!';
  }
  
  targetElt
    .find('a')
    .contents()
    .unwrap()
    .wrap(function() {
      var linkText  = $(this).text(),
          spanClass = linkText == linkText.toUpperCase() 
                      ? ' class="link-span"' 
                      : '';
      return '<span' + spanClass + '></span>';
    });
  
  return targetIsString ? targetElt.html() : void(0);
}

Working with Different targetElt Types in jQuery

In order to handle three different data/object types, we have to perform some up-front checks to determine which type was supplied.

Testing for a primitive string can be done using the typeof operator. While this approach doesn't handle proper String objects, that isn't one of the accepted argument types anyway. We can't use typeof to check for an HTMLElement because it would evaluate to an "object". Instead, we can employ instanceof. The instanceof operator tests to see if the prototype property of a constructor appears anywhere in the prototype chain of an object.

The instanceof approach works equally well to test for a jQuery object because the jQuery function (aka $()) is implemented as a constructor. When you invoke $(foo), internally jQuery translates this to new jQuery.prototype.init(foo). JavaScript proceeds to initialize this inside the constructor function to point to a new instance of jQuery, setting its properties to those found on jQuery.prototype (aka jQuery.fn).

Extracting the Contents between  a and /a Link Tags

I spoke about the jQuery contents() method in theFiltering IFrame Content using jQuery article. As explained there:

It searches through the immediate children of the element collection and constructs a new jQuery object from the matching elements. It's similar to the children() method, except that contents() includes text nodes as well as HTML elements in the resulting jQuery object.

Link Unwrapping with jQuery

No, this section does not include a new YouTube video showing off the latest tech gadget. This unwrapping refers to the jQuery unwrap() method. It removes the parents of the element (or element collection) from the DOM, leaving the matched element(s) in its/their place. The best part about unwrap() is that it mutates the original DOM so that the elements are actually removed.

Once link elements have been unwrapped, we can rewrap them in a new parent element using wrap(). Moreover, wrap() can accept a function so that we can decide which type of parent element to use or, in our case, add a class for custom CSS styling.

Handling HTML Strings

Raw HTML strings require different handling than HTMLElements or jQuery objects because there is no DOM to work with. To overcome that issue, we can simply create a DIV element and set its HTML content to the passed string: $('<div></div>').html(htmlContent);. Likewise, the modified HTML must be returned from the function. HTMLElements or jQuery objects do not require the linksToSpans() function to return anything because it modifies the underlying DOM via the this pointer.

I'm not keen on putting the return statement inside of an if block, so I used the ternary operator to either return the targetElt's HTML content (targetElt.html()) or void(0). I could have returned the undefined primitive value as well.

Conclusion

In this tutorial, we saw how jQuery makes replacing DOM elements so much easier than it would be otherwise by writing a function that replaces links with spans. Here's a demo that shows the linksToSpans() function in action:

See the Pen Replace HTML Elements using jQuery Demo by Rob Gravelle (@blackjacques) on CodePen.

Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Home
Mobile Site | Full Site