Select2 doesn't work on Meteor

Hey guys,

I have been trying to get select2 to work on Meteor for quite some time, but still no success. I tried the NPM package, then I switched to natestrauser:select2, then I experimented both - and neither of these options worked.

NPM-only: I get (…).select2( ) is not a function
natestrauser:select2-only: I don’t get an error, but select2 isn’t loaded anyway
Both together: Same thing as only natestrauser:select2

In all cases, the output is just a bootstrap select-box (the same thing I get without select2).

My code looks like this:

HTML

 <div class="form-group mb-3">
    <select id="select-tag" class="select2 form-control select2-multiple" data-toggle="select2" 
         multiple="multiple" data-placeholder="Choose ...">
             <option value="AK">Alaska</option>
             <option value="HI">Hawaii</option>
    </select>
 </div>

JS

Template.Tags.onRendered(function () {

    $('[data-toggle="select2"]').select2();

});

I tried many different selectors for .select2( ). The id, the classes… nothing worked.

Any ideas?

Thanks!

For the npm version, how are you importing it?

import select2 from 'select2';

I just checked one of my projects that does use Select2, and the npm module doesn’t export the right thing, so you need to pick out the compiled js file (and the css) and that exports a factory function that you need to pass jQuery into to initialise it.

Putting it together:

import select2 from 'select2/dist/js/select2';
import 'select2/dist/css/select2.css';
import 'select2-bootstrap-theme/dist/select2-bootstrap.css';

import { jQuery } from 'meteor/jquery';
// Select2 needs to be globally initialized because it exports a factory function and does not init itself
select2(window, jQuery);

And of course the documentation doesn’t say any of this… What a pain :tired_face:
I’d totally forgotten about all this


I have this in a setupSelect2 file that I import wherever select2 is required. Putting it in a separate file just helps with dependency management when using bundle splittng

1 Like

Now that is surprisingly complicated!
I did as you wrote and now Meteor recognizes the existance of select2 (doesn’t show me the error anymore). However, it still doesn’t initialize… could you share with me your jquery selector and html?

Thanks!

I differ on the above method, I import it dynamically in an onRendered function.

import("../select2.js").then(({default: select2}) => {
import "../select2.css";
$(".select2").select2({
    minimumResultsForSearch: 2,
    width: "100%",
    matcher: function(term, text) {
      return text.toUpperCase().indexOf(term.toUpperCase()) == 0;
    }
  });

Html:

<select id="cname" name="type" class="form-control select2 form-control-lg" placeholder="Select Corpus Name">
 <option></option>
 {{#each cname}}
   <option value="{{this}}">{{this}}</option>
 {{/each}}
</select>
2 Likes

Here’s the selector:

Template.mediaLibraryDashboard.onRendered(function() {
    this.$('.searchByTag').select2();
});

@jh65592, have you copied the source of select2 directly into your project?
Looking at the import path makes me think you have?

import("../select2.js")
1 Like

Yes, I copied from the dist folder on Github and place in the ui directory one-level up from the html pages directory.

Still can’t get it to work… it looks like Meteor is completely ignoring the select2 call… it’s there (because I don’t receive any alerts), but it doesn’t generate any effect

Maybe your problem is that when the onRendered hook fires your #each loop isn’t done yet?

 {{#each cname}}
   <option value="{{this}}">{{this}}</option>
 {{/each}}
1 Like

I’m not using {{#each}} … for testing purposes I am just hardcoding the option tags

The following worked for me

Template.select2template.onRendered(async function select2onRendered() {
    import jQuery from 'jquery/dist/jquery';
    import 'select2/dist/css/select2.min.css';
    import select2 from 'select2/dist/js/select2';
    select2(window, jQuery);

    this.$('select').select2();
});
1 Like

@jamgold

When using your solution, select2 does work, but only 1 out of ~20 times I load the template - the other times, the select tag is rendered without it…

I finally got it to work! My solution was:

  • Use the Atmosphere package (natestrauser:select2) instead of the one from NPM
  • Create an async check that guarantees that the DOM element is already loaded when select2 is applied

HTML

<div class="form-group mb-3" id="select-tag-div">
      <select class="select-tag-dropdown" id="select-tag" name="state">
              <option value="AL">Alabama</option>
              <option value="WY">Wyoming</option>
      </select>
</div>

JS

Template.Select2Box.onRendered(async function select2onRendered(){

    function rafAsync() {
        return new Promise(resolve => {
            requestAnimationFrame(resolve); //faster than set time out
        });
    }

    async function checkElement(selector) {
        while (!document.getElementById(selector)) {
            await rafAsync()
        }
        return true;
    }

    checkElement('select-tag')
        .then(() => {
            $('.select-tag-dropdown').select2();
        });

});

Thanks guys! :slight_smile: