How to detect if search term used on select2? - jquery-select2

I'm trying to create a searchable list using select2. So far, I have it working - but I want to tweak it more. This is the code I have:
$('#allowed_cat_ids').select2( { templateSelection: formatList, templateResult: formatSearch });
function formatSearch (state) {
if (!state.id) {
return state.text;
}
var $state = $(
'<span>' + state.element.getAttribute('data-full-path') + '</span>'
);
return $state;
};
function formatList (state) {
if (!state.id) {
return state.text;
}
var $state = $(
'<span>' + state.element.getAttribute('data-full-path') + '</span>'
);
return $state;
};
My dropdown looks like: (trimmed down, as its a long list)
<select name="allowed_cat_ids[]" id="allowed_cat_ids" multiple="multiple">
<option value="3199" data-full-path="Region">Region</option>
<option value="3445" data-full-path="Region/Africa"> Africa</option>
<option value="3446" data-full-path="Region/Africa/Kenya"> Kenya</option>
<option value="3458" data-full-path="Region/Africa/Kenya/Car Rental"> Car Rental</option>
<option value="3457" data-full-path="Region/Africa/Kenya/Lodging"> Lodging</option>
<option value="3461" data-full-path="Region/Africa/Kenya/Restaurants"> Restaurants</option>
<option value="3456" selected="selected" data-full-path="Region/Africa/Kenya/Travel"> Travel</option>
<option value="3459" data-full-path="Region/Africa/Kenya/Travel/Tour"> Tour</option>
<option value="3460" data-full-path="Region/Africa/Kenya/Travel/Tour/Safari"> Safari</option>
<option value="3719" data-full-path="Region/Africa/Rwanda"> Rwanda</option>
<option value="3467" data-full-path="Region/Asia"> Asia</option>
<option value="3707" data-full-path="Region/Asia/Israel"> Israel</option>
<option value="3605" data-full-path="Region/Asia/Palestine"> Palestine</option>
</select>
What I want to do is:
When showing the list (without a search term), it will show using the   indenting I have. This is so it shows up nicely like:
When selected, I want it to show up with the value from data-full-path, which it currently does fine:
When actually doing a search, I want it to show the FULL category path (not the one with the padding in). The reason for this, is that is when you search otherwise, all you see if the non-full category name:
I have this kinda working - but the problem is that templateResult changes the template for:
a) The dropdown (without a search term)
b) When you do a search
So my endgame I guess - is that I want to see if there is a search term, and format it differently - something like:
if (search_term_here) {
$state = $(
'<span>' + state.text + ' </span>'
);
} else {
$state = $(
'<span>' + state.element.getAttribute('data-full-path') + ' </span>'
);
}
return $state;
Hopefully that make sense!

Related

Always display placeholder select2

I would like to build a selector that displays a "Check one or more or options" placeholder and, after selecting 1-N options, the placeholder is still displayed instead of the checked results.
In short, the component should always display the placeholder, regardless of having 0, 1 or N options checked.
I have been searching but I can't find any way to do it:
Html:
<select multiple id="e1" style="width:300px">
<option value="AL">Alabama</option>
<option value="Am">Amalapuram</option>
<option value="An">Anakapalli</option>
<option value="Ak">Akkayapalem</option>
<option value="WY">Wyoming</option>
</select>
Js
$('select').select2({
placeholder: "Select a state",
templateSelection: function (data) {
return 'Select a state';
}
});
http://jsfiddle.net/91nqgkuy/2/
Finally, I have chosen to overwrite the results template and insert the desired text.
// Set the default option.
$(select, context).each(function (e) {
setTemplateResults($(this));
});
// Override select2 default work flow.
$(select, context).on('select2:select select2:unselect', function (evt) {
setTemplateResults($(this));
});
// Method.
function setTemplateResults(selector) {
let container = selector.siblings('span.select2').find('ul')
container.html('<li>' + Drupal.t('Select category(ies)') + '</li>');
}

Displaying images in select2 based on data attributes on options

I want to do something with Select2 like the templating example but I'm not using a predefined set of images so need to modify it somewhat.
I thought I could add the path to the image I want to display with a data attribute on each option and then instead of element.value I could use element.attr('data-thumb') but when I do that I get element.attr is not a function
HTML
<select>
<option value="A" data-thumb="a.jpg">A</option>
<option value="B" data-thumb="b.jpg">B</option>
<option value="C" data-thumb="c.jpg">C</option>
</select>
JS
function productStyles(selection) {
if (!selection.id) { return selection.text; }
var $selection = $(
'<img src="' + selection.element.attr('data-thumb')+ '"> ' + selection.text
);
return $selection;
};
$('.img-changer').select2({
templateResult: productStyles
});
Is it possible to access data attributes using .element or do I need another approach and if so, what would that be?
Turns out what I needed was var thumb = $(selection.element).data('thumb').
function productStyles(selection) {
if (!selection.id) { return selection.text; }
var thumb = $(selection.element).data('thumb');
if(!thumb){
return selection.text;
} else {
var $selection = $(
'<img src="' + thumb + '" alt=""><span class="img-changer-text">' + $(selection.element).text() + '</span>'
);
return $selection;
}
}
<option class="img class" value=""></option>
function formatSelect2(o) {
if (!o.id)
return o.text;
else
return $("<span><i class='" + $(o.element).attr("class") + "'></i> " + o.text + "</span>"); }
$('#Category-Add').select2({
width: '100%',
templateResult: formatSelect2,
templateSelection: formatSelect2,
theme: "classic"
});

JQM Change Select icon to Notext

In trying to keep website responsive I want to hide the text from a select menu when the screen is below a certain size.
I use something similar to remove button text.
function resizeBtn() {
var activePage = $.mobile.pageContainer.pagecontainer("getActivePage");
if ($(window).width() <= 490) {
$("#opt_user_btn.ui-btn-icon-left", activePage).toggleClass("ui-btn-icon-notext ui-btn-icon-left");
$( "#storeselect", activePage ).selectmenu( "option", "iconpos", "notext" );
} else {
$("#opt_user_btn.ui-btn-icon-notext", activePage).toggleClass("ui-btn-icon-left ui-btn-icon-notext");
$( "#storeselect", activePage ).selectmenu( "option", "iconpos", "notext" );
}
}
And the html is along the lines of:
<form><select name="storeselect" id="storeselect" data-native-menu="true" data-iconpos="left" onChange="this.form.submit();" >
<option value="1">1</option>
<option value="2">2</option>
</select>
</form>
I've looked at JQM info but not figured it out yet. Help would be appreciated. Thank you. :)
Inspecting the select bar the text for the selected option is in a span tag. One solution is to add a class with opacity:0 to the span
<div id="storeselect-button" class="ui-btn ui-icon-carat-d ui-btn-icon-left ui-corner-all ui-shadow"><span>Option 1</span><select name="storeselect" id="storeselect" data-native-menu="true" data-iconpos="left">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select></div>
Demo
http://jsfiddle.net/mjk0f0t7/
Jquery
$(window).on('resize change', function () {
if ($(window).width() <= 490) {
$("#storeselect-button").find("span").addClass("noshow")
} else {
$("#storeselect-button").find("span").removeClass("noshow");
}
});
Css
.noshow {
opacity:0;
}
To hide or style the icon also
$("#storeselect").append('<style>.ui-btn-icon-left:after{opacity:0}</style>');
Demo
http://jsfiddle.net/wuLccyda/
To add ui-btn-icon-notext class simply use addClass and refresh the select menu
$(window).on('resize', function () {
if ($(window).width() <= 490) {
$("#storeselect").addClass("ui-btn-icon-notext")
$('#storeselect').selectmenu('refresh', true);
} else {
$("#storeselect").removeClass("ui-btn-icon-notext")
$('#storeselect').selectmenu('refresh', true);
}
});
Demo
http://jsfiddle.net/ywp70xtc/

Select2 with a checkbox list for a multiple select

I need to implement a select similar to this http://www.erichynds.com/examples/jquery-ui-multiselect-widget/demos/
I want to use select2 for this, but I haven't been able to find anything from the creator of the select2 that would support this style of dropdown with checkboxes in it. Does anyone know a way to do this?
I've faced a similar need but was not able to find it.
The solution I've came across was using the flag closeOnSelect set to false
$("#yadayada").select2({closeOnSelect:false});
http://jsfiddle.net/jEADR/521/
Seems this is old post, but as it is very common issue, I`m posting this here.
I found that the author already added a plugin to select2 for this feature to have checkbox-like selection and the dropdown does not hide on click:
https://github.com/wasikuss/select2-multi-checkboxes
Example:
$('.select2-multiple').select2MultiCheckboxes({
placeholder: "Choose multiple elements",
})
http://jsfiddle.net/wasikuss/gx93rwnk/
All other features of select2 are preserved. There are few more predefined options set to work properly.
I managed to put something together, not perfect, but it works.
https://jsfiddle.net/Lkkm2L48/7/
jQuery(function($) {
$.fn.select2.amd.require([
'select2/selection/single',
'select2/selection/placeholder',
'select2/selection/allowClear',
'select2/dropdown',
'select2/dropdown/search',
'select2/dropdown/attachBody',
'select2/utils'
], function (SingleSelection, Placeholder, AllowClear, Dropdown, DropdownSearch, AttachBody, Utils) {
var SelectionAdapter = Utils.Decorate(
SingleSelection,
Placeholder
);
SelectionAdapter = Utils.Decorate(
SelectionAdapter,
AllowClear
);
var DropdownAdapter = Utils.Decorate(
Utils.Decorate(
Dropdown,
DropdownSearch
),
AttachBody
);
var base_element = $('.select2-multiple2')
$(base_element).select2({
placeholder: 'Select multiple items',
selectionAdapter: SelectionAdapter,
dropdownAdapter: DropdownAdapter,
allowClear: true,
templateResult: function (data) {
if (!data.id) { return data.text; }
var $res = $('<div></div>');
$res.text(data.text);
$res.addClass('wrap');
return $res;
},
templateSelection: function (data) {
if (!data.id) { return data.text; }
var selected = ($(base_element).val() || []).length;
var total = $('option', $(base_element)).length;
return "Selected " + selected + " of " + total;
}
})
});
});
CSS:
.select2-results__option .wrap:before{
font-family:fontAwesome;
color:#999;
content:"\f096";
width:25px;
height:25px;
padding-right: 10px;
}
.select2-results__option[aria-selected=true] .wrap:before{
content:"\f14a";
}
Add just two emoji with css
.select2-results__options {
&[aria-multiselectable=true] {
.select2-results__option {
&[aria-selected=true]:before {
content: '☑';
padding: 0 0 0 4px;
}
&:before {
content: '◻';
padding: 0 0 0 4px;
}
}
}
}
You see this sample a RTL select2 with emoji based checkbox
Here is very simple snippet, without strange modyfing of js - pure and simple css (with "Font Awesome")
$('.select2[multiple]').select2({
width: '100%',
closeOnSelect: false
})
#body{
padding: 30px
}
.select2-results__options[aria-multiselectable="true"] li {
padding-left: 30px;
position: relative
}
.select2-results__options[aria-multiselectable="true"] li:before {
position: absolute;
left: 8px;
opacity: .6;
top: 6px;
font-family: "FontAwesome";
content: "\f0c8";
}
.select2-results__options[aria-multiselectable="true"] li[aria-selected="true"]:before {
content: "\f14a";
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/css/select2.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/js/select2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/js/all.min.js"></script>
<div id="body">
<select name="fabric_color_en[]" id="fabric_color_en[]" multiple="multiple" class="form-control select2">
<option value="Beige">
Beige
</option>
<option value="Red">
Red
</option>
<option value="Petrol">
Petrol
</option>
<option value="Royal Blue">
Royal Blue
</option>
<option value="Dark Blue">
Dark Blue
</option>
<option value="Bottle Green">
Bottle Green
</option>
<option value="Light Grey">
Light Grey
</option>
</select>
</div>
Now the code is ready to use for you to implement the multiple checkboxes select2 dropdown.
Enjoy :)
//===============================================
//Start - Select 2 Multi-Select Code======================================================
var Select2MultiCheckBoxObj = [];
var id_selectElement = 'id_SelectElement';
var staticWordInID = 'state_';
function AddItemInSelect2MultiCheckBoxObj(id, IsChecked) {
if (Select2MultiCheckBoxObj.length > 0) {
let index = Select2MultiCheckBoxObj.findIndex(x => x.id == id);
if (index > -1) {
Select2MultiCheckBoxObj[index]["IsChecked"] = IsChecked;
}
else {
Select2MultiCheckBoxObj.push({ "id": id, "IsChecked": IsChecked });
}
}
else {
Select2MultiCheckBoxObj.push({ "id": id, "IsChecked": IsChecked });
}
}
function IsCheckedAllOption(trueOrFalse) {
$.map($('#' + id_selectElement + ' option'), function (option) {
AddItemInSelect2MultiCheckBoxObj(option.value, trueOrFalse);
});
$('#' + id_selectElement + " > option").not(':first').prop("selected", trueOrFalse); //This will select all options and adds in Select2
$("#" + id_selectElement).trigger("change");//This will effect the changes
$(".select2-results__option").not(':first').attr("aria-selected", trueOrFalse); //This will make grey color of selected options
$("input[id^='" + staticWordInID + "']").prop("checked", trueOrFalse);
}
$(document).ready(function () {
//Begin - Select 2 Multi-Select Code
$.map($('#' + id_selectElement + ' option'), function (option) {
AddItemInSelect2MultiCheckBoxObj(option.value, false);
});
function formatResult(state) {
if (Select2MultiCheckBoxObj.length > 0) {
var stateId = staticWordInID + state.id;
let index = Select2MultiCheckBoxObj.findIndex(x => x.id == state.id);
if (index > -1) {
var checkbox = $('<div class="checkbox"><input class="select2Checkbox" id="' + stateId + '" type="checkbox" ' + (Select2MultiCheckBoxObj[index]["IsChecked"] ? 'checked' : '') +
'><label for="checkbox' + stateId + '">' + state.text + '</label></div>', { id: stateId });
return checkbox;
}
}
}
let optionSelect2 = {
templateResult: formatResult,
closeOnSelect: false,
width: '100%'
};
let $select2 = $("#" + id_selectElement).select2(optionSelect2);
//var scrollTop;
//$select2.on("select2:selecting", function (event) {
// var $pr = $('#' + event.params.args.data._resultId).parent();
// scrollTop = $pr.prop('scrollTop');
// let xxxx = 2;
//});
$select2.on("select2:select", function (event) {
$("#" + staticWordInID + event.params.data.id).prop("checked", true);
AddItemInSelect2MultiCheckBoxObj(event.params.data.id, true);
//If all options are slected then selectAll option would be also selected.
if (Select2MultiCheckBoxObj.filter(x => x.IsChecked === false).length === 1) {
AddItemInSelect2MultiCheckBoxObj(0, true);
$("#" + staticWordInID + "0").prop("checked", true);
}
});
$select2.on("select2:unselect", function (event) {
$("#" + staticWordInID + "0").prop("checked", false);
AddItemInSelect2MultiCheckBoxObj(0, false);
$("#" + staticWordInID + event.params.data.id).prop("checked", false);
AddItemInSelect2MultiCheckBoxObj(event.params.data.id, false);
});
$(document).on("click", "#" + staticWordInID + "0", function () {
//var b = !($("#state_SelectAll").is(':checked'));
var b = $("#" + staticWordInID + "0").is(':checked');
IsCheckedAllOption(b);
//state_CheckAll = b;
//$(window).scroll();
});
$(document).on("click", ".select2Checkbox", function (event) {
let selector = "#" + this.id;
let isChecked = Select2MultiCheckBoxObj[Select2MultiCheckBoxObj.findIndex(x => x.id == this.id.replaceAll(staticWordInID, ''))]['IsChecked'];
$(selector).prop("checked", isChecked);
});
});
//====End - Select 2 Multi-Select Code==
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.6.0/dist/js/bootstrap.bundle.min.js" integrity="undefined" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>
<div class="container-fluid">
<hr/>
<p>Here, you can select any item by clicking on row or checked in on checkbox and can unselect in reverse way.</p>
<p>But I didn't give the option to select "SelectAll" option by clicking on his row, you can select-all and unselect-all by click on checkbox only rather than row.</p>
<div class="row" style="width:50%">
<label for="id_SelectElement" class="col-sm-2">Part Name: </label>
<div class="col-sm-4">
<select id="id_SelectElement" placeholder="Select Text" multiple>
<option value="0" disabled>Select All</option>
<option value="11">Php</option>
<option value="22">Bootstrap</option>
<option value="33">sql</option>
<option value="44">Node Js</option>
<option value="55">Laravel</option>
<option value="66">Jquery</option>
<option value="77">React</option>
<option value="88">Vew.JS</option>
<option value="99">MVC</option>
<option value="10">DotNetCore</option>
<option value="12">Java</option>
<option value="13">Artifical Intiligence</option>
<option value="14">Data Structure</option>
<option value="15">Data Science</option>
<option value="16">Robotics</option>
<option value="17">Node Js 2</option>
<option value="18">Laravel 23</option>
<option value="19">Jquery 3.4</option>
</select>
</div>
</div>
</div>
Another workaround is to "prepend" checkbox icons using CSS. I use bootstrap theme - your select2-container may be different.
.select2-container--bootstrap .select2-results__option[aria-selected=true]:before { content:'\e067 '; padding:0 8px 0 0px; font-family:'Glyphicons Halflings' }
.select2-container--bootstrap .select2-results__option:before { content:'\e157 '; padding:0 8px 0 0px; font-family:'Glyphicons Halflings' }

Icons in Custom jQuery Mobile Select Menu

I'm using a custom select menu from jQuery Mobile, and I'd like to put icons into the custom pop-up menu to accompany each option. I'm applying the data-icon attribute to each option, like so:
<select name='mySelect' id='mySelect' data-icon='gear'>
<option value='0' data-icon='star'>Option 0</option>
<option value='1' data-icon='star'>Option 1</option>
<option value='2' data-icon='star' selected="selected">Option 2</option>
</select>
FWIW, I've already verified that my custom icons work in the select button itself. Am I just completely wrong in expecting icons to appear in the custom menu?
This is not supported by default but here is a quick piece of code to make it possible:
//wait for the correct page to initialize
$(document).delegate('#home', 'pageinit', function () {
//loop through each of the SELECT elements in this page
$.each($(this).find('select'), function () {
//get the ID of this select because it's menu's ID is based off of it
var currentID = this.id;
//iterate through each of the OPTION elements for this SELECT element
$.each($(this).find('option'), function (index, element) {
//if the OPTION element has the `data-icon` attribute
if ($(element).attr('data-icon') != undefined) {
//update the menu for this SELECT by adding an icon SPAN element
//to each of the OPTION elements that has a `data-icon` attribute
$('#' + currentID + '-menu').children().eq(index).find('.ui-btn-inner').append('<span class="ui-icon ui-icon-' + $(element).attr('data-icon') + ' ui-icon-shadow" />');
}
});
});
});​​
Here is a demo: http://jsfiddle.net/NHQGD/

Resources