Home > Back-end >  Reloading JS scripts on page (transition) change when using Barba JS
Reloading JS scripts on page (transition) change when using Barba JS

Time:01-02

I'm trying to implement barba.js on a HubSpot site.

Consider the following two pages:

  1. Resources
  2. Customers

With my current barba.js implementation, this is the current flow I'm experiencing:

  1. I access the resources page (not by transitioning to it, by directly accessing it via /resources).
  2. At this point, all my js is working (slick-sliders, scroll functions etc)
  3. I then use the navigation to access the customers page. The page loads, but all of the js specific to modules and forms for that page are not working.

In short, js for pages that I transition to do not work.

To resolve this, what I'm trying to do is to reload all scripts within the container beforeEnter().

See below:

$(function() {

  function delay(n){
    n = n || 2000;
    return new Promise((done) => {
      setTimeout(() => {
        done();
      }, n);
    });
  }

  barba.init({
    sync: true,
    prefetchIgnore: true,
    debug: true,
    transitions: [{

      async leave(data){
        const done = this.async();
        await delay(200);
        done();
      },

      async beforeEnter({ next, container }) {

        $(container).find('script').each(function (i, script) {
          var $script = $(script);
          $.ajax({
            url: $script.attr('src'),
            cache: true,
            dataType: 'script',
            success: function () {
              $script.trigger('load');
            }
          });
        });
      },

      async enter(data){
        let scrollX = 0
        let scrollY = 0

        barba.hooks.leave(() => {
          scrollX = barba.history.current.scroll.x;
          scrollY = barba.history.current.scroll.y;
        });

        window.scrollTo(scrollX, scrollY);
      },

      async once(data){
        console.log("done");
      },

    }]
  });

});

However, my current beforeEnter() still yields the same results. Any way around this?

Edit

To provide more details, this barba.js implementation is for a HubSpot site. When you create custom modules in HubSpot it spits out the JS for that module on the page (in script tags). For example, here is how JS is rendered on the page:

<script>
    // js from custom module is here
</script>

<script src=".../scripts-min.min.js"></script>

As such, when a barba transition is executed, I need all JS that have src and those that are rendered inline (like custom modules) to reload.

Latest approach based on User863's feedback

$(function() {

  function delay(n){
    n = n || 2000;
    return new Promise((done) => {
      setTimeout(() => {
        done();
      }, n);
    });
  }

  function reload_scripts(param){
    $(param).find('script').each(function (i, script) {
      var $script = $(script);
      $.ajax({
        url: $script.attr('src'),
        cache: true,
        dataType: 'script',
        success: function () {
          $script.trigger('load');
          console.log("scripts loaded");
        }
      });
    });
  }


  barba.init({
    sync: true,
    prefetchIgnore: true,
    debug: true,
    transitions: [{

      async leave(data){
        const done = this.async();
        await delay(200);
        done();
      },

      async beforeEnter(data) {
        reload_scripts(data.next.container);
      },

      async beforeEnter({ next }) {
        reload_scripts(next.container);
      },

      async enter(data){
        // scroll to top of page when transitioning
        let scrollX = 0
        let scrollY = 0

        barba.hooks.leave(() => {
          scrollX = barba.history.current.scroll.x;
          scrollY = barba.history.current.scroll.y;
        });

        window.scrollTo(scrollX, scrollY);
      },

      async once(data){
        console.log("transition complete");
      },

    }]
  });

});

Current behaviour: Same as before (scripts for modules are broken when page changes). Modules with slick slider's for example, do not work (slick isn't initiated).

CodePudding user response:

Might be solved by using eval as mentioned here: https://github.com/barbajs/barba/issues/32

Mentioned in the comments on the issue:

barba.hooks.after((data) => {
    let js = data.next.container.querySelectorAll('main script');
    if(js != null){
            js.forEach((item) => {
                console.log(js)
                eval(item.innerHTML);
            });
    }
});

CodePudding user response:

According to docs

The arguments of beforeEnter transition will be object of

Property Description
data.current Current page related
data.next Next page related
data.trigger Link that triggered the transition

https://barba.js.org/docs/advanced/hooks/#data-properties

Therefore the container property available inside both data.current and data.next properties. In this case, we have to use script from data.next which related to a new page.

Fixed code #1

async beforeEnter(data) {

    $(data.next.container).find('script').each(function (i, script) {
        // ...
    })
}

Fixed code #2

async beforeEnter({ next }) {

    $(next.container).find('script').each(function (i, script) {
        // ...
    })
}
  • Related