Barba JS with Sage 9

Hey guys,

Just want to say that I think Sage is amazing. It’s been making developing on WordPress an absolute joy from beginning to end. It will be my go to moving forward. The routing based system is awesome except in this moment right here :sweat_smile:. For anyone using Barba JS version 2. I hopefully want this to be help for others. This took me a bit of getting used to.

Context

Because of Sage’s routing system and Barba’s ajax calls to other pages, you run into a problem where once you get to the next page, you will see your elements but won’t have the required CSS or JS run because of the body class. @philipp did an amazing job above using version 1 and this example I give is a continuation of it but for barba version 2.

1. Setting up a proper barba-container.

<div class="vendors-container" data-barba='wrapper'>
        <div class="container" id="content-container" data-barba="container" data-barba namespace="one-pager">
   <div id="body-classes" @php(body_class())>
         ...Put here the content you wish to change between pages...
   </div>
  </div>
</div>

Above, you will see that version 2 now requires attributes data-barba and data-barba-namespace. This is used similarly to @philipp’s example. Inside, you are creating an empty div that will hold the body classes of the body of the page you are transitioning to.

Tip: Make sure that the body_class div has an ID rather than a class. I made the mistake of having it:

<div class="body-classes"></div>

The body_class() function does not output anything if classes are already there… There is 30 minutes gone of my time lol.

2. Proper Initialization.

Before I had a barba v2 initialization in the common.js folder. Instead, I followed @philipp’s example and created it in assets/scripts/barbainit.js. The code is here:

import barba from '@barba/core';
import anime from 'animejs';

export default function(routes) {
  barba.init({
    transitions: [
      {
        name: 'one-pager-transition',
        to: {
          namespace: ['one-pager'],
        },
        leave(data) {
          return new Promise(resolve => {
            jQuery(data.current.container).hide(function() {
              anime({
                // Animation details (I use anime.js but you could use GSAP here)
                complete: function() {
                  // Callback function for when the animation is complete
                  // Barba JS v2 is promise based, so you need to call resolve() to move on to the enter part
                  resolve();
                },
              });
            });
          });
        },
        enter: ({ next }) => {
          return new Promise(resolve => {
            anime({
              // animation parameters
              complete: function() {
                // Set new classes from #af-classes to body
                jQuery('body').attr(
                  'class',
                  jQuery('#body-classes').attr('class')
                );
                // Fire routes again after new content loaded
                routes.loadEvents();
                resolve();
              },
            });
          });
        },
      },
    ],
  });
}

This is a redo of @philipp function but redone in Barba v2. We basically are taking the initialization method of barba v2 and exporting it as a function to put in the main.js file. If you are unaware of how this works have a look at the docs for BarbaJS. Basically, it’s promise based, where once we get the new “container” we are taking the body classes of that container that we did in the last step and applying to the body of the dom in it’s current state. Then, we reinitialize the loadEvents() method which triggers the routing based files of your choosing (CSS, JS etc).

3. Loading into your main.js file

Import:

import barbaInit from './barbainit';

Then plug er in to the loadEvents() function.

jQuery(document).ready(() => {
  routes.loadEvents();
  barbaInit(routes);
});

Here it’s loading the loadEvents like Sage normally does but then triggers barbaInit from the last step, which does the animation, replace the body with new body classes and reruns the loadEvents() like it did a page refresh.

Excellent example by @philipp. Hopefully this has been a little helpful.

Code could be optimized more… considering that you will have to put a #body-classes block in every template. You would also have to do step 2 for every single animation you do if you have more than one transition like I do lol.

Cheers.

4 Likes