RequireJS, AngularJS and jQuery Living Together

We have a project where we are already using RequireJS to dynamically load JavaScript.  The project is on the Sitecore platform and we are bundling our renderings with their supporting client-side code.  First we call RequireJS in the head tag.

<script data-main="/Content/Foo/js/config" src="/Content/Vendor/RequireJS/2.1.15/require.js"></script>

Then if I have a interactive component, like a carousel, we define a script tag just below the markup.

<div class="carousel">
...
</div>

require(['config'], function () {
    require(['modules/carousel/init']);
})
</script>

One of the pages we’re developing calls for an in-page navigation with some tabs that show different content.  AngularJS routing is a perfect fit for this.  But to further complicate our particular case, we have a few interactive pieces inside each of those routing views.  One such piece is an accordion and we’d also like to use jQuery to implement it (we tried the AngularJS equivalent, it wasn’t perfect).  That jQuery code would have to execute only after that partial routing view was loaded.  Here’s how we made it happen.

We have directory structure as such:

  • app.js
  • controllers
    • firstTab.js
    • secondTab.js
    • thirdTab.js

“app.js” is the file that defines our AngularJS module and each file in “controllers” defines a specific controller that will be used in the routing configuration.  A single controller, with the RequireJS wrapper, looks like this:

define(['jquery', '../app'], function ($, app) {
    app.controller('FirstTabController', function ($scope) {
        $scope.$on('$viewContentLoaded', function (event) {
            $('.accordion__switch').click(function (e) {
                e.preventDefault();
                $(this).toggleClass('active').next().slideToggle('slow');
            });
        });
    });
})

We bring in jQuery with the alias of “$” since that’s what most people are used to.  The key is putting an event handler on $viewContentLoaded.  After that, the jQuery code is pretty straight forward.

As a bonus, we actually have accordions on multiple views.  So ideally, we would put our jQuery code in a separate function, include it via RequireJS and execute it as needed.  So we define a file “accordionInit.js”

define(['jquery'], function($){
    return function(event){
        $('.accordion__switch').click(function(e) {
            e.preventDefault();
            $(this).toggleClass('active').next().slideToggle('slow');
        });
    }
})

And then modify our original controller.

define(['jquery', '../app', '../accordionInit'], function ($, app, accordionInit) {
    app.controller('FirstTabController', function ($scope) {
        $scope.$on('$viewContentLoaded', accordionInit);
    });
})

I think this plays to a number of each library’s strengths.  AngularJS prides itself on being “embeddable” in so much as it doesn’t interfere with other libraries’ internals, has no dependencies and you can choose to use as much or as little of it as you need.  RequireJS allows you to break up all the elements into their own discrete containers and include them when appropriate.  And it’s tough to argue that there’s a better and more tested library for doing interactive components than jQuery.  It’s even better when you can get them to all come together in harmony.

Do you see something we’re overlooking or got wrong?  Feel free to leave a message or offer an alternative approach.  Is this something you would use?

Leave a Reply