Developer forum

Forum » Swift » variant change not triggering complete page reload

variant change not triggering complete page reload

Christoffer Rosendahl Frede
Reply

Hi everyone.

i discovered a kind of odd issue. i am testing on Dynamicweb version 10.23.1 and using Swift version v2.1.0

when i change the variant on a productpage it seems like it does not get completely reloaded. when i inspect the document, it looks like javascript

replaces the <main></main> content with the new variant data. but the entire <head></head> element stays the same. does anyone know if that is working as intended ?

or is there some Ecom settings or other settings, that can change this behaviour ?

/best regards Christoffer

 


Replies

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply
This post has been marked as an answer

It is intended - as we designed to make the UX flow fine.

When you do it, the page content changes fast and interactively - but the header section does not. The URL does change - and if you reload the page, the header section is for the variant as well. 

Our JS fires events - you should be able to overrule how we navigate - below untested version of how that can be done.
 

There is an interception point: selectioncomplete.swift.variantselector is fired before the URL update + PageUpdater.Update(...) fetch happens, and it’s cancelable (our code checks dispatchEvent(...) != false). So you can create a script that calls preventDefault() and do a full navigation instead.

Option A (best): cancel the async swap and do a real page load to the selected variant

Drop this on the product page (after Swift scripts are loaded):

<script>
(function () {
  function buildVariantUrl(variantSelectorEl, selections) {
    // Mirror Swift logic: base-url OR current URL with variantid param
    var variantid = selections.join(".");
    var baseUrl = variantSelectorEl.getAttribute("data-base-url");

    if (baseUrl) {
      // baseUrl is already a full URL (often includes querystring)
      return baseUrl + "&variantid=" + encodeURIComponent(variantid);
    }

    var url = new URL(window.location.href);
    url.searchParams.set("variantid", variantid);
    return url.toString();
  }

  // Attach locally to each selector so we can access e.target reliably
  document.querySelectorAll(".js-variant-selector").forEach(function (vs) {
    vs.addEventListener("selectioncomplete.swift.variantselector", function (e) {
      // Stop Swift from calling PageUpdater.Update(...)
      e.preventDefault();

      var url = buildVariantUrl(vs, e.detail && e.detail.selections ? e.detail.selections : []);

      // Full reload (updates <head>, canonical, meta, structured data, etc.)
      window.location.href = url;
    });
  });
})();
</script>

How this works:

  • selectioncomplete.swift.variantselector is dispatched before window.history.replaceState(...) and before PageUpdater.Update(variantSelectorElement) is called.

  • Because it’s cancelable: true, e.preventDefault() makes dispatchEvent(...) return false, and your code short-circuits the inline update.

Option B (fallback): let it swap inline, then immediately reload the page

This is the “brute force” version: it allows the fetch + DOM swap, then reloads. It’s less efficient (double work), but sometimes partners prefer “no logic, just reload”.

<script>
(function () {
  // Fires after fetch completed and HTML is available (but before swap decision completes)
  document.addEventListener("updated.swift.pageupdater", function () {
    window.location.reload();
  }, { once: true });
})();
</script>

Notes:

  • updated.swift.pageupdater is fired after the fetch returns HTML (response.text()), right before/around the replacement path.

  • If you want to reload after the DOM has been replaced, hook swapped.swift.pageupdater instead (it’s dispatched after innerHTML = html in Success).

Tiny gotcha worth calling out

If you use Option B, make it { once: true } (as above) or you can get reload loops if other parts of the page also trigger page updates.

Votes for this answer: 1
 
Christoffer Rosendahl Frede
Reply

Thank you Nicolai.

it seems to work. i dropped the first script Option A in ProductDetailRenderGrid.cshtml.

i am not 100% sure that is the right place to put it? 

 

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

That location is as good as any. That location makes it work exactly in that context only, so that seems like a fine place.

BR Nicolai

 
Christoffer Rosendahl Frede
Reply

Great thanks.

The issue without this script seems to be that if tracking is used pageviews does not trigger properly.

we also had customer who was copying links after a variant change where the titles was incorrect. i am not sure how they copied the link though.

but great that we have a workaround now. 

 
Christoffer Rosendahl Frede
Reply

Oh. with the script now the url is not pretty anymore. is there any way to modify: var url = buildVariantUrl(vs, e.detail && e.detail.selections ? e.detail.selections : []);

now on our swift 2 demo we get this: /shop?GroupID=GROUP155&ProductID=6110830688M&variantid=VO14

instead of this: shop/bikes/all-bikes/scultura-9000-e/l

 

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Try to check the code that makes the URL. It should always use the base URL.

Try this one - otherwise spend 10 mins debugging it.

function buildVariantUrl(variantSelectorEl, selections) {
  var variantid = selections.join(".");
  var baseUrl = variantSelectorEl.getAttribute("data-base-url");

  if (baseUrl && typeof baseUrl !== "string") {
    console.log("baseUrl is not a string:", baseUrl);
  }

  // Always use baseUrl as the starting point
  var url = new URL(baseUrl);
  url.searchParams.set("variantid", variantid);

  return url.toString();
}

 

You must be logged in to post in the forum