Select2 add image icon to option dynamically
Asked Answered
P

6

20

This is what select2.github.io gives you:

function addIcons(opt) {
    if (!opt.id) {
        return opt.text;
    }
    var $opt = $(
            '<span><img src="/images/flags/' + opt.element.value.toLowerCase() + '.png" class="img-flag" /> ' + opt.text + '</span>'
            );
    return $opt;
}

I'd like to add a data-image attribute to my options:

<option value="flag" data-image="/images/flags/flag.png">Country 1</option>

and log it in the function:

function addIcons(opt) {
    if (!opt.id) {
        return opt.text;
    }

    var optimage = opt.attr('data-image');
    var $opt = $(
            '<span><img src="/images/flags/' + optimage + '" class="img-flag" /> ' + opt.text + '</span>'
            );
    return $opt;
}

Sadly, a simple console.log(opt); doesn't return anything in the function, so I can't see if I can access my data-image attribute. The above block of code returns an error, so this obviously doesn't work. Any suggestions on this matter?

Pilewort answered 26/3, 2015 at 22:59 Comment(2)
An error? What's the specific error message? Do you have a jsfiddle demo?Meloniemelony
to get the data value use $(opt.element).attr('data-image');Dedans
T
23

Solved using attr and tested on Select2 4.0.6-rc.0.

$(".class").select2({
    templateResult: formatState,
    templateSelection: formatState
});

function formatState (opt) {
    if (!opt.id) {
        return opt.text.toUpperCase();
    } 

    var optimage = $(opt.element).attr('data-image'); 
    console.log(optimage)
    if(!optimage){
       return opt.text.toUpperCase();
    } else {                    
        var $opt = $(
           '<span><img src="' + optimage + '" width="60px" /> ' + opt.text.toUpperCase() + '</span>'
        );
        return $opt;
    }
};
Taster answered 30/7, 2018 at 18:57 Comment(0)
D
16

If optimage returns "undefined" try my sample: its working fine:

$("#selectUserForChat").select2({
  templateResult: addUserPic,
  templateSelection: addUserPic
});

function addUserPic(opt) {
  if (!opt.id) {
    return opt.text;
  }
  var optimage = $(opt.element).data('image');
  if (!optimage) {
    return opt.text;
  } else {
    var $opt = $(
      '<span class="userName"><img src="' + optimage + '" class="userPic" /> ' + $(opt.element).text() + '</span>'
    );
    return $opt;
  }
};
Denten answered 14/1, 2016 at 9:11 Comment(0)
V
9

I solved problem with this code: var optimage = $(opt.element).data('image');

$(".category").select2({
            templateResult: formatState,
            templateSelection: formatState
        });
        function formatState (opt) {
            if (!opt.id) {
                return opt.text;
            }               
            var optimage = $(opt.element).data('image'); 
            if(!optimage){
                return opt.text;
            } else {                    
                var $opt = $(
                    '<span><img src="' + optimage + '" width="23px" /> ' + opt.text + '</span>'
                );
                return $opt;
            }

        };
Viridis answered 8/10, 2015 at 12:35 Comment(2)
That is the same as in my example, and that didn't work: var optimage = opt.attr('data-image');Pilewort
I try to complete answerViridis
M
3

Try this:

var optimage = $(opt).data('image'); //or $(opt).attr('data-image')
var $opt = $(
    '<span><img src="' + optimage + '" class="img-flag" /> ' + $(opt).text() + '</span>'
);
Meloniemelony answered 26/3, 2015 at 23:6 Comment(1)
optimage returns "undefined". I have tried it this way too.Pilewort
C
0

Not necessarily related to the question, but in my case it wasn't working because if you are using Select 2 < 4.0, templateResult and templateSelection does not exist. Use formatResult and formatSelection instead.

Compatriot answered 26/3, 2018 at 19:0 Comment(0)
R
0

Every single answer here is incorrect as it exposes your application to an XSS vulnerability when returning a jQuery object to select2. Let's read the docs and find out why:

Built-in escaping

By default, strings returned by templateResult are assumed to contain only text and will be passed through the escapeMarkup function, which strips any HTML markup.

If you need to render HTML with your result template, you must wrap your rendered result in a jQuery object. In this case, the result will be passed directly to jQuery.fn.append and will be handled directly by jQuery. Any markup, such as HTML, will not be escaped and it is up to you to escape any malicious input provided by users.

Looking at the other answers, they all have the fatal flaw of not escaping the text before passing it back. Instead the correct code should look like this (assuming a proper escape function, I used lodash in my circumstance):

$(".class").select2({
    templateResult: formatState,
    templateSelection: formatState
});

function formatState (opt) {
    if (!opt.id) {
        return opt.text;
    } 

    var optimage = $(opt.element).attr('data-image'); 
    if(!optimage) {
       // This is safe, since you're returning a string
       return opt.text;
    } else {
       // Create an individual image element to properly escape the src url
       var img = $("<img width='60px'>");
       img.attr("src", optimage);

       // And remember to escape the text we're outputing
       var $opt = $(
         '<span>' +
         img.prop('outerHTML'); +
         '" width="60px" /> ' + 
         escape(opt.text) + 
         '</span>'
       );
       return $opt;
    }
};
Registrant answered 9/8, 2022 at 3:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.