3

I am trying to set up a test and am having trouble replacing an element with another. I am doing this through an enterprise CRO testing platform.

The page that the test is being built on: https://medcline.com/products/shoulder-relief-pillow

On the right of the image carousel, you'll see a table. This table exists within a div with the class "description".

I am trying to replace that table, using the class "description," with tabbed content but I cannot get it to work. My code:

<script type="text/JavaScript">
  var myAnchor = document.getElementsByClassName("description");
  var mySpan = document.createElement("div");
  mySpan.innerHTML = "<div class="tab">
  <button class="tablinks" onclick="openPerk(event, 'Relief')" id="defaultOpen">Relief</button>
  <button class="tablinks" onclick="openPerk(event, 'Features')">Features</button>
</div>

<div id="Relief" class="tabcontent">
  <p><strong>Wake up refreshed!</strong> This patented, three-component Sleep System naturally relieves nighttime shoulder pain so you can sleep better at night and feel better during the day.</p>
<p>Do you experience nighttime acid reflux? For patients with both shoulder pain and nighttime acid reflux, we recommend the <strong><a href="https://medcline.com/products/medcline-reflux-relief-system">MedCline Reflux Relief System</a></strong>.</p>
</div>

<div id="Features" class="tabcontent">
  <ul><li>Patented arm pocket for pain free sleep</li>
  <li>FSA/HSA approved</li>
  <li>95% of usuers report better sleep</li>
  <li>Left- or right-side use</li></ul>
</div>";
  myAnchor.parentNode.replaceChild(mySpan, myAnchor);

  function openPerk(evt, perkName) {
  var i, tabcontent, tablinks;
  tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }
  tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }
  document.getElementById(perkName).style.display = "block";
  evt.currentTarget.className += " active";
  }
  document.getElementById("defaultOpen").click();
</script>

Thank you for any and all help.

  • 1
    Are you having any JS errors? This line seems off to me: `mySpan.innerHTML = "
    ` Maybe wrap `'tab'` on single quotes.
    – Hanlet Escaño Aug 02 '21 at 18:19
  • 3
    Using `.innerHTML` with massive amounts of static markup is ill advised. In fact using `.innerHTML` at all is really something to be avoided due to performance and security concerns. Instead, consider just adding that HTML to the page in the first place. Also, don't use [`getElementsByClassName()`](https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474), use `.querySelectorAll()` instead. – Scott Marcus Aug 02 '21 at 18:25
  • Thanks, Scott. That's probably easier -- figuring this out due to limited dev support and to A/B test. – Jonathan Finegold Catalán Aug 05 '21 at 19:25

1 Answers1

0

1. Escaped Line Breaks/Template Literals

The first change which is most apparent is to modify the mySpan.innerHTML section: the HTML string does not work as is because single- and double-quotes do not support unescaped line breaks. You can escape line breaks or use template literals to resolve this.

A. Escaped Line Breaks

Changing all of the unescaped line breaks to \n will resolve the issue. It may not be as readable, but there's nothing wrong with this approach.

mySpan.innerHTML = "<div class=\"tab\">\n  <button class=\"tablinks\" onclick=\"openPerk(event, 'Relief')\" id=\"defaultOpen\">Relief</button>\n<!-- ... -->\n</div>";

Note: escaping double quotes is also needed in the string so that it will not result in a syntax error.

B. Template Literals

Using template literals, any line breaks between the backticks are interpreted the same way as the escaped line breaks.

mySpan.innerHTML = `<div class="tab">
  <button class="tablinks" onclick="openPerk(event, 'Relief')" id="defaultOpen">Relief</button>
<!-- ... -->
</div>`;

2. HTMLCollection, not Element

Another slight error is that the myAnchor variable is an HTMLCollection (getElementsByClassName returns an HTMLCollection even if there is only one result), so it will not have a parentNode property.

Changing the assignment expression to reference the first element in the HTMLCollection resolves this:

var myAnchor = document.getElementsByClassName("description")[0];

Full Solution

The following code snippet borrows elements necessary from the webpage referenced to show a working example of the changes listed above.

const myAnchor = document.getElementsByClassName("description")[0];
const mySpan = document.createElement("div");
mySpan.innerHTML = `<div class="tab">
      <button class="tablinks" onclick="openPerk(event, 'Relief')" id="defaultOpen">Relief</button>
      <button class="tablinks" onclick="openPerk(event, 'Features')">Features</button>
    </div>
  
    <div id="Relief" class="tabcontent">
      <p><strong>Wake up refreshed!</strong> This patented, three-component Sleep System naturally relieves
      nighttime shoulder pain so you can sleep better at night and feel better during the day.</p>
      <p>Do you experience nighttime acid reflux? For patients with both shoulder pain and nighttime acid reflux, we recommend the
      <strong><a href="https://medcline.com/products/medcline-reflux-relief-system">MedCline Reflux Relief System</a></strong>.</p>
    </div>
  
    <div id="Features" class="tabcontent">
      <ul>
        <li>Patented arm pocket for pain free sleep</li>
        <li>FSA/HSA approved</li>
        <li>95% of usuers report better sleep</li>
        <li>Left- or right-side use</li>
      </ul>
    </div>`;
myAnchor.parentNode.replaceChild(mySpan, myAnchor);

function openPerk(evt, perkName) {
  let i;
  const tabcontent = document.getElementsByClassName("tabcontent");
  for (i = 0; i < tabcontent.length; i++) {
    tabcontent[i].style.display = "none";
  }
  const tablinks = document.getElementsByClassName("tablinks");
  for (i = 0; i < tablinks.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" active", "");
  }
  document.getElementById(perkName).style.display = "block";
  evt.currentTarget.className += " active";
}
window.openPerk = openPerk;
document.getElementById("defaultOpen").click();
<div class="seven columns medium-down--one-whole omega">
  <div class="sale_banner_product">Sale</div>
  <h1 class="product_name">MedCline Shoulder Relief System</h1>
  <div data-oke-reviews-product-listing-rating="">
    <div data-oke-reviews-version="2.13.0" class="okeReviews okeReviews--theme">
      <div class="okeReviews-reviewsSummary js-okeReviews-reviewsSummary is-okeReviews-clickable" data-oke-ga-click-action="Star Rating Summary Click" data-oke-ga-click-label="MedCline Shoulder Relief System" tabindex="0" role="button">
        <div class="okeReviews-reviewsSummary-starRating">
          <span class="okeReviews-starRating okeReviews-starRating--small">
            <span class="okeReviews-a11yText">Rated 4.2 out of 5</span>
          <span class="okeReviews-starRating-indicator" role="presentation">
              <span class="okeReviews-starRating-indicator-layer"></span>
          <span class="okeReviews-starRating-indicator-layer okeReviews-starRating-indicator-layer--foreground" style="width: 85%"></span>
          </span>
          </span>
        </div>
        <div class="okeReviews-reviewsSummary-ratingCount">
          <span aria-hidden="true">364 Reviews</span>
          <span class="okeReviews-a11yText">Based on 364 reviews</span>
        </div>
        <span class="okeReviews-a11yText">Click to go to reviews</span>
      </div>
    </div>
  </div>
  <div class="feature_divider"></div>
  <div class="modal_price">
    <div class="price__container price__container--display-price-false "> <span content="199.99" class="sale"> <span class="current_price"> <span class="money">$199.99</span></span>
      </span> <span class="was_price"> $249.99</span> <span class="sale savings"> You Save 20% (<span class="money">$50.00</span>)</span>
    </div>
    <div class="sold-out__container"> <span class="sold_out"></span></div>
  </div>
  <div class="description">
    <div class="desktop-only">
      <b></b>
      <table class="compare_table" id="lp_blue" style="width: 100%;">
        <tbody>
          <tr>
            <th></th>
            <th>MedCline</th>
            <th>The Other Guys</th>
          </tr>
          <tr>
            <td>Patented Arm Pocket for Pain Free Sleep</td>
            <td>✓</td>
            <td>✕</td>
          </tr>
          <tr>
            <td>FSA/HSA Approved</td>
            <td>✓</td>
            <td>✕</td>
          </tr>
          <tr>
            <td>95% of Users Report Better Sleep</td>
            <td>✓</td>
            <td>✕</td>
          </tr>
          <tr>
            <td>Left or Right-Side Use</td>
            <td>✓</td>
            <td>✕</td>
          </tr>
        </tbody>
      </table>
    </div>
    <dl class="faqAccordion right-for-you mobile-only">
      <dt><button type="button" aria-expanded="false">How MedCline compares to the competition</button></dt>
      <dd id="panel-05" aria-hidden="true">
        <table style="width: 100%;" id="lp_blue" class="compare_table">
          <tbody>
            <tr>
              <th></th>
              <th>MedCline</th>
              <th>The Other Guys</th>
            </tr>
            <tr>
              <td>Patented Arm Pocket for Pain Free Sleep</td>
              <td>✓</td>
              <td>✕</td>
            </tr>
            <tr>
              <td>FSA/HSA Approved</td>
              <td>✓</td>
              <td>✕</td>
            </tr>
            <tr>
              <td>95% of Users Report Better Sleep</td>
              <td>✓</td>
              <td>✕</td>
            </tr>
            <tr>
              <td>Left or Right-Side Use</td>
              <td>✓</td>
              <td>✕</td>
            </tr>
          </tbody>
        </table>
      </dd>
    </dl>
  </div>
  <div class="clearfix product_form init smart-payment-button--false  product_form--dropdown" id="product-form-4791002857607" data-product-form="" data-options-size="1" data-money-format="${{amount}}" data-shop-currency="USD" data-select-id="product-select-4791002857607"
    data-enable-state="true" data-product="" data-product-id="4791002857607">
    <form method="post" action="/cart/add" id="product_form_4791002857607" accept-charset="UTF-8" class="shopify-product-form" enctype="multipart/form-data"><input type="hidden" name="form_type" value="product"><input type="hidden" name="utf8" value="✓"> <input type="hidden" name="id" value="33912967626887">
      <div class="purchase-details">
        <div class="purchase-details__quantity product-quantity-box"> <label for="quantity">Qty</label> <span class="ss-icon product-minus js-change-quantity" data-func="minus"><span class="icon-minus"></span></span> <input type="number" min="1" size="2" class="quantity" name="quantity" id="quantity" value="1">          <span class="ss-icon product-plus js-change-quantity" data-func="plus"><span class="icon-plus"></span></span>
        </div>
        <div class="purchase-details__buttons purchase-details__spb--false ">
          <a class="bundleupgrade__trigger quick-pay-off" js-trigger-bundle="">ADD TO CART</a> <button type="button" name="add" class=" ajax-submit action_button add_to_cart  " data-label="Add to Cart"> <span class="text"> Add to Cart</span> <svg x="0px" y="0px" width="32px" height="32px" viewBox="0 0 32 32" class="checkmark">
              <path fill="none" stroke-width="2" stroke-linecap="square" stroke-miterlimit="10" d="M9,17l3.9,3.9c0.1,0.1,0.2,0.1,0.3,0L23,11"></path>
            </svg></button>
        </div>
        <shopify-payment-terms variant-id="33912967626887" shopify-meta="{&quot;variants&quot;:[{&quot;id&quot;:33912967626887,&quot;price&quot;:&quot;$49.99&quot;,&quot;eligible&quot;:true}],&quot;min_price&quot;:&quot;$50&quot;,&quot;max_price&quot;:&quot;$3000&quot;}"></shopify-payment-terms>
        <div class="cf-order-by-outer" style="display:none;"> Order NOW and get it by:&nbsp;<span class="cf-order-by-date"></span></div>
      </div>
    </form>
  </div>
</div>
phentnil
  • 2,195
  • 2
  • 14
  • 22