0

I have a RequireJS setup that loads the Select2 jQuery plugin.

I have an issue however that means on page load, the browser default select input is shown for a few seconds, and then swapped out for the advanced Select2 input presumably as RequireJS is loading my scripts asynchronously.

Is there a way I can avoid this without having to include the script in the HTML?

This is my RequireJS setup:

require.config({
baseUrl: '/assets/js',
paths: {
    jquery: '//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min',
    async: 'libs/async',
    modernizr: 'libs/modernizr-custom',
    jqueryUI: 'libs/jquery-ui.min',
    bootstrap: 'libs/bootstrap.min',
    select2: 'libs/select2.min',
},
shim: {
    'select2': {
        deps: ['jquery'],
        exports: 'Select2'
    },
    'bootstrap': {
        deps: ['jquery'],
        exports: 'Bootstrap'
    },
    'jqueryUI': {
        deps: ['jquery'],
        exports: 'jQueryUI'
    },
}
});

requirejs(["app/polyfills"]);
requirejs(["app/filter"]);
requirejs(["app/select"]); // Select2 plugin trigger
requirejs(["app/datepicker"]);
requirejs(["app/popover"]);
requirejs(["app/dropdown"]);
requirejs(["app/tooltip"]);
requirejs(["app/layout"]);
requirejs(["app/menu"]);
requirejs(["app/toggles"]);

And this is the actual script:

define(['select2'], function(Select2) {

    var app = {};

    app.select = (function(){
        var module = {};

        module.init = function(){

            $(".select-advanced").select2({
                width: 'off',
                dropdownAutoWidth: 'true',
            });
        };

        return module;
    })();

    $(document).ready(function(){
        app.select.init();
        console.log('select');
    });

}); 
jshjohnson
  • 157
  • 4
  • 16

2 Answers2

0

There is no way to force RequireJS to load a module right away. It is an implementation of the Asynchronous Module Definition API. So there is no guarantee regarding when modules are loaded. Some options:

  1. Load Select2 with a <script> element in the <head> instead of RequireJS. This would entail loading all its dependencies with <script> elements too.

  2. Use Almond to load your application. While RequireJS cannot force modules to be loaded right away, Almond can take a series of AMD modules and load them synchronously. However, it comes with several limitations and it would be a significant change to what you are doing now. It is unclear whether it would work for your application. I've discussed Almond here and here.

  3. Modify your application so that the parts of the DOM that depend for their appearance on modules loaded by RequireJS are invisible until the modules are loaded. I've recently done this with a page that uses AngularJS. The HTML contains markup which is parsed by AngularJS. Before I made the necessary changes, when the page was first loaded, the markup would to the user and looked ugly. I modified the page so that the sensitive part of the page starts with a style of display: none and remove it once Angular has loaded. I find the transition from invisible to visible to be acceptable.

I've generally used the third option.

Community
  • 1
  • 1
Louis
  • 146,715
  • 28
  • 274
  • 320
  • Sorry - I meant include, not inline (i've edited the question). Option 3 works for me as I am not supporting users with JS turned off. Thanks – jshjohnson Oct 30 '14 at 12:42
  • Glad to help! I've removed the parenthesis on inlining to sync my answer with the new state of the question. :) – Louis Oct 30 '14 at 12:44
-1

One way would be to hide the select and show it once select2 has done loading.

Working example http://jsfiddle.net/9wk33bLo/

HTML

<select id="e1" style="display: none">

JS

$.when(
    $("#e1").select2({
        width: 'off',
        dropdownAutoWidth: 'true'
})).done(function () {
    this.select2("container").show();
});
Primož
  • 24
  • 3