Question:
What I intend to do is that when selecting one of the options, the text of the parent (optgroup) is placed and it shows me something like " LG / Lg – Test 1 " (notice in the example that I put that "LG" is the parent (optgroup ) and "Lg – Test 1" is the child (option)) and I want to make it so that the user can see which parent (optgroup) they are selecting.
In the example that I place, the formatDataSelection
function is the one that is in charge of placing the text when selecting an option.
Here is the code of what I have:
var data = {"results":[{"text":"LG","children":[{"id":1,"text":"Lg - Prueba 1"},{"id":2,"text":"Lg - Prueba 2"}]},{"text":"Samsung","children":[{"id":3,"text":"Sam - Prueba 1"},{"id":4,"text":"Sam - Prueba 2"}]}],"pagination":{"more":false}};
$("select").select2({
placeholder: "Elija...",
allowClear: true,
data: data.results,
escapeMarkup: function (markup) { return markup; },
templateResult: formatData,
templateSelection: formatDataSelection
});
function formatData (data) {
if (data.loading) return data.text;
return data.text;
}
function formatDataSelection (data) {
return data.text;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/css/select2.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/js/select2.min.js"></script>
<select style="width: 100%"></select>
The answer that the user @JuankGlezz gave me, led me to this other problem: The text of the parent label of the selected option is not obtained.
$('select').select2({
placeholder: "Elija...",
allowClear: true,
ajax: {
type: "GET",
dataType: 'json',
url: 'https://api.myjson.com/bins/12apr1',
delay: 250,
data: function(params) {
return {
term: params.term, // search term
page: params.page || 1, //page number
}
},
processResults: function (data, page) {
return {
results: $.map(data.results, function (n) {
return {
text: n.text,
children: n.children
}
}),
//results: data.results,
pagination: {
more: data.pagination.more,
}
};
},
cache: true
},
escapeMarkup: function (markup) { return markup; },
templateResult: crear_marca_modelo_formatData,
templateSelection: crear_marca_modelo_formatDataSelection
});
function crear_marca_modelo_formatData (data) {
if (data.loading) return data.text;
return data.text;
}
function crear_marca_modelo_formatDataSelection (data) {
let labelOptg = $(data.element).parent().attr('label');
return labelOptg + " / " + data.text;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/css/select2.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/js/select2.min.js"></script>
<select style="width: 100%"></select>
Answer:
If you look at the DOM that is created when generating your second script, it is not the typical one with optgroup
but it creates one with the following form:
<li .... role="group" aria-label="Life Good">
<strong ...> Life Good </strong>
<ul ....>
<li ....> Lg Prueba 1 </li>
<li ....> Lg Prueba 2 </li>
</ul>
</li>
Therefore, when referring to the parent element you are not referring to the optgroup
(as you currently have it in your example) but to the ul
.
I have also been able to observe that each of the elements of the select
when you select them obtain a certain class called .select2-results__option--highlighted
, so I have used this class to refer to the element that we have just selected.
Later, and seeing how the DOM takes on the structure once the dropdown is generated, I am going to scale two positions using .parent().parent()
to get to the li
, although I am going to filter so that I only get the elements with role="group"
by doing the filter .find("[role='group']")
.
Lastly, I'll get the prevObject
element to detect which one is before the element we just selected and I'll get its aria-label
attribute.
Additionally: I have also made a condition so that if there is no element that has been selected, undefined... / Elija...
does not appear and only the word Elija...
appears so that it is seen in a much more "friendly" way .
Your modified example:
$('select').select2({
placeholder: "Elija...",
allowClear: true,
ajax: {
type: "GET",
dataType: 'json',
url: 'https://api.myjson.com/bins/12apr1',
delay: 250,
data: function(params) {
return {
term: params.term, // search term
page: params.page || 1, //page number
}
},
processResults: function (data, page) {
return {
results: $.map(data.results, function (n) {
return {
text: n.text,
children: n.children
}
}),
//results: data.results,
pagination: {
more: data.pagination.more,
}
};
},
cache: true
},
escapeMarkup: function (markup) { return markup; },
templateResult: crear_marca_modelo_formatData,
templateSelection: crear_marca_modelo_formatDataSelection
});
function crear_marca_modelo_formatData (data) {
if (data.loading) return data.text;
return data.text;
}
function crear_marca_modelo_formatDataSelection (data) {
if(data.element !== undefined){
if($(".select2-results__option--highlighted").parent().parent().find("[role='group']").prevObject[0]){
var etiquetaOptGroup = $(".select2-results__option--highlighted").parent().parent().find("[role='group']").prevObject[0].getAttribute("aria-label");
return etiquetaOptGroup + " / " + data.text;
}
}else{
let labelOptg = $(data.element).parent().attr('label');
return data.text;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/css/select2.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2/js/select2.min.js"></script>
<select style="width: 100%"></select>
UPDATE: According to the comments, the problem is deselecting an element that has already been selected, since it causes problems that it cannot obtain the getAttribute
of a null element.
Since both creating and deleting an element from the dropdown uses the same function, I have created a new condition that only uses the getAttribute
function if the object exists to solve the error:
if(data.element !== undefined){
if($(".select2-results__option--highlighted").parent().parent().find("[role='group']").prevObject[0]){
//Aqui obtiene el atributo cuando el objeto existe y lo añade al desplegable
}
}else{
//Código cuando data viene como undefined
}
In this way we would solve the error. I've edited the example above so you can see that it no longer throws an error when deselecting dropdown items.