Barba JS with Sage 9

Did someone successfully managed to incorporate Barba JS into Sage 9?

I can only get Barba JS working if I include all the code in common.js (see image below)

I can not figure out what is the best way to separate the code according to the sage 9 routing system.

I already tried to separate by file in routes/x.js, but I had problems and Barba JS did not always run.

I am aware of the other topics in the subject, but the users did not clarify the structure they used, as I think they manipulated the routing system a bit

Libraries like this don’t reload the page, they load via ajax, which would therefore affect the JS routing system. Sage JS uses the body class for routing, and checks this on each page load. You will probably need to fire JS functions using one of Barba.js events

Barba.Dispatcher.on('newPageReady', function(currentStatus, oldStatus, container) {

});

Also, check this out with regards to what @withjacoby said: http://barbajs.org/views.html

I did that once with sage. As far as I remember I did the following:

1.) Add another div into the ajax loaded content which get’s the correct classes via @php(body_class()). So in the dom it could be:

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

1.) Add a new folder & file under assets/scripts/barba/init.js so separate the code and use something like:

import Barba from 'barba.js/dist/barba';

    export default function (routes) {
        Barba.Pjax.Dom.wrapperId = 'barba-wrapper';
        Barba.Pjax.Dom.containerClass = 'barba-container';

        // Blacklist all WordPress Links (e.g. for adminbar)
        function addBlacklistClass() {
            $( 'a' ).each( function() {
                if ( this.href.indexOf('/wp-admin/') !== -1 ||
                    this.href.indexOf('/wp-login.php') !== -1 ) {
                    $( this ).addClass( 'no-barba' ).addClass( 'wp-link' );
                }
            });
        }

        // Set blacklist links
        addBlacklistClass();

        // Fire Barba.js
        Barba.Pjax.start();
        Barba.Prefetch.init();

        Barba.Dispatcher.on('transitionCompleted', function() {

            // Set new classes from #af-classes to body
            $('body').attr('class', $('#body-classes').attr('class'));

            // Fire routes again after new content loaded
            routes.loadEvents();
        });

3.) In main.js load the barba/init.js

// import barba.js init script
import barbaInit from './barba/init';

4.) To load barba.js and to fire the correct routes after ajax loaded content, you’ll need to modify in main.js:

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

I hope that helps.

3 Likes

Where would you fire the Barba.Dispatcher on the Sage configuration though?

What have you tried?

This is my structure:

init.js: init.js · GitHub
home.js: home.js · GitHub
main.js: main.js · GitHub

Please also share you app.blade.php here. I guess your DOM is not as described under my point 1.

app.blade.php · GitHub

Hi @yunik ! I was wondering if you could walk us/me through how you set up barbra.js in Sage 9.0 (if you got it working that is)? I’m somewhat new to Sage (I’ve used sage 5.0 for a while and moving to 9.0 with blade) and would love to know how you set it up.

Hi @philipp, thanks for that excellent post up top, I followed your steps, but I’m getting an Uncaught TypeError: Cannot read property ‘Dom’ of undefined inside the init.js. Was hoping you might be able to shine some light on my error. You can see my files below

1.) Add a new folder & file under assets/scripts/barba/init.js so separate the code:

2.) Add a new folder & file under assets/scripts/barba/init.js:

3.) In main.js load the barba/init.js:

4.) To load barba.js and to fire the correct routes after ajax loaded content:

Hi @raltamirano,

sorry for my late reply. As I see Barba.js is currently in a very active development phase and reached version 2. My example above is based on version 1.0.0 and I am afraid that I do not have enough time to go through it at the moment.
The code is based on this documentation for v1: https://barba.js.org/v1/
For v2 you can find a very rough documentation here: https://barba.js.org/docs/v2/user/
Maybe you can find the differences and update the code for your needs. Otherwise I recommend starting with v1 and update to v2 as soon as they published some instructions.

Best,

Philipp

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

Hi @elebumm. Thank you very much for the updates! That looks very promising and I’m looking forward to test version 2 very soon.

Best,

Philipp

Hi @elebumm Thank you so much for this info!!!

1 Like

About the <body> classes part, I’m using this code:

barba.hooks.afterLeave((data) => {
  // Set <body> classes for "next" page
  // Based on https://github.com/barbajs/barba/issues/51#issuecomment-276721590
  var nextHtml = data.next.html;
  var response = nextHtml.replace(/(<\/?)body( .+?)?>/gi, '$1notbody$2>', nextHtml)
  var bodyClasses = $(response).filter('notbody').attr('class')
  $("body").attr("class", bodyClasses);
});

What do you think about?

1 Like

I think You can use DomParser

barba.hooks.beforeEnter(data => {
  if(data && data.next && data.next.html) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(string, "text/html");
    if( doc.body ) {
      let classes = doc.body.getAttribute('class');
      document.body.setAttribute('class', classes);
    }
  }
});