Select2 with multiple nested groups
Asked Answered
M

4

13

I'm having trouble using the Select2 with various groups, only the latter appears.

<select name="txtConta" id="txtConta" data-placeholder="Selecione a conta">         
    <option value=""></option>
    <option value="S11892">2 - Gastos</option>
    <option value="S11893">2.1 - DESPESA OPERACIONAL FIXA</option>
    <option value="S11895">2.1.1 - PESSOAL</option>
    <option value="S11915">2.1.1.1 - GERENCIA/ADMINSTRATIVO</option>
    <option value="11916">2.1.1.1.1 - SAL&#193;RIOS</option>
    <option value="11917">2.1.1.1.2 - DIVIDENDOS / COMISS&#213;ES /BONUS</option>
    <option value="11918">2.1.1.1.3 - INSS</option>
    <option value="11919">2.1.1.1.4 - FGTS</option>
    <option value="11920">2.1.1.1.5 - IRRF COD. 0561</option>
    <option value="11921">2.1.1.1.6 - PLANO DE SAUDE</option>
    <option value="11922">2.1.1.1.7 - TICKET REFEICAO</option>
    <option value="11923">2.1.1.1.8 - VALE TRANSPORTE</option>
    (...)
</select>

<script>
$('select').each(function () {
    $(this).select2({
        allowClear: true,
        width: 'resolve',
        dropdownAutoWidth: true
    });
});

$('#txtConta').find('option').each(function () {
    if ($(this).attr("value").indexOf('S') == 0) {
        $('<optGroup/>').attr('label', $(this).text()).appendTo($('#txtConta'));
        $(this).remove();
    } else {
        $('#txtConta').find('optGroup').last().append($(this));
    }
});
</script>

You can see a demonstration in this jsfiddle.

Maxia answered 1/10, 2014 at 17:14 Comment(0)
M
19

This solution was tested using select2 version 4.0.1, and you can do this way:

  1. Pass one array that contains one attribute more (the level of every node in the hierarchy). The array's structure is simple

  2. Create a function to format results,that is, how looks like every item according its level inside of hierarchy

  3. When initialize select, set the function created to attribute templateResult

You can see in the follow code:

  $(document).on("ready", function() {
  var data = [{
    id: "2",
    text: "2 - Gastos",
    level: 1
  }, {
    id: "2.1",
    text: "2.1 - DESPESA OPERACIONAL FIXA",
    level: 2
  }, {
    id: "2.1.1",
    text: "2.1.1 - PESSOAL",
    level: 3
  }, {
    id: "2.1.1",
    text: "2.1.1 - PESSOAL",
    level: 4
  }, {
    id: "2.1.1.1",
    text: "2.1.1.1 - GERENCIA/ADMINSTRATIVO",
    level: 4
  }, {
    id: "2.1.1.1.1",
    text: "2.1.1.1.1 - SALÁRIOS",
    level: 5
  }, {
    id: "2.1.1.1.2",
    text: "2.1.1.1.2 - DIVIDENDOS / COMISSÕES /BONUS",
    level: 5
  }, {
    id: "2.1.1.1.3",
    text: "2.1.1.1.3 - INSS",
    level: 5
  }, {
    id: "2.1.1.1.4",
    text: "2.1.1.1.4 - FGTS",
    level: 5
  }];

  function formatResult(node) {
    var $result = $('<span style="padding-left:' + (20 * node.level) + 'px;">' + node.text + '</span>');
    return $result;
  };

  $("#mySelect").select2({
    placeholder: 'Select an option',
    width: "600px",
    data: data,
    formatSelection: function(item) {
      return item.text
    },
    formatResult: function(item) {
      return item.text
    },
    templateResult: formatResult,
  });
});
<!DOCTYPE html>

<html>

<head runat="server">
  <title></title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.2-rc.1/css/select2.min.css" rel="stylesheet" />
</head>

<body>
  <select id="mySelect">
  </select>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.1/js/select2.full.min.js"></script>
</body>
</html>
Morrell answered 23/2, 2016 at 21:13 Comment(3)
Hi, I tried you code, and it works for me. but I have one problem, that the list is not sorted. How can I overcome this problem??Nnw
How can I set a selected option??Nnw
@Nnw You can set a selected option with the plugin select2 using: $('#mySelect2').val('1'); // Select the option with a value of '1' $('#mySelect2').trigger('change'); // Notify any JS components that the value changed See select2.org/programmatic-control/add-select-clear-itemsMorrell
I
8

I used like this. Working Fine.

$(document).on("ready", function() {
  function formatResult(node) {
    var level = 0;
    if(node.element !== undefined){
      level = (node.element.className);
      if(level.trim() !== ''){
        level = (parseInt(level.match(/\d+/)[0]));
      }
    }
    var $result = $('<span style="padding-left:' + (20 * level) + 'px;">' + node.text + '</span>');
    return $result;
  };

  $("#select2").select2({
    placeholder: 'Select an option',
    width: "300px",
    templateResult: formatResult,
  });
});
<!DOCTYPE html>

<html>

<head runat="server">
  <title></title>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
</head>

<body>
  <select id="select2" data-placeholder="Select an option" tabindex="-1" aria-hidden="true">
  <option></option>
  <optgroup label="Base">
    <option class="level_0" value="0">Base Parent</option>
  </optgroup>
  <option class="level_1" value="11">A</option>
  <option class="level_2" value="12">Ant</option>
  <option class="level_3" value="15">Fire Ant</option>
  <option class="level_2" value="14">Apple</option>
  <option class="level_1" value="13">B</option>
</select>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
</body>
</html>
Instant answered 12/7, 2017 at 5:37 Comment(1)
Works perfekt. Nice solution if your datasource is HTML rather than JSON.Bleak
E
5

Take a look at this GitHub issue. What matters is

HTML itself forbids nesting <optgroup>s, so your markup is invalid before it even reaches Select2. However, you can arbitrarily nest choices via children when you use JS objects to represent the choices.

This means that you can use children to get multiple nested options. The following solution and jsfiddle are based on fperie's solution.

<input name="txtConta" id="txtConta" data-placeholder="Selecione a conta" />     

<script>
var data = [
    {id: "2", name: "2 - Gastos", children: [
        {id: "2.1", name: "2.1 - DESPESA OPERACIONAL FIXA", children: [
            {id: "2.1.1", name: "2.1.1 - PESSOAL", children: [
                {id: "2.1.1", name: "2.1.1 - PESSOAL"}, 
                {id: "2.1.1.1", name: "2.1.1.1 - GERENCIA/ADMINSTRATIVO", children: [
                    {id: "2.1.1.1.1", name: "2.1.1.1.1 - SALÁRIOS"},
                    {id: "2.1.1.1.2", name: "2.1.1.1.2 - DIVIDENDOS / COMISSÕES /BONUS"},
                    {id: "2.1.1.1.3", name: "2.1.1.1.3 - INSS"},
                    {id: "2.1.1.1.4", name: "2.1.1.1.4 - FGTS"}
                ]}
            ]}
        ]}
    ]}
    ];

$('#txtConta').select2({
    allowClear: true,
    width: 'resolve',
    dropdownAutoWidth: true,
    width: '400px',
    data: {results: data, text: "name"}, 
    formatSelection: function(item) { 
        return item.name 
    }, 
    formatResult: function(item) { 
        return item.name 
    }
});
</script>

With this solution the leafs are still selectable. If you don't want to select the leafs you should remove the id attribute from the leafs.

See this JSfiddle that demonstrates both configurations. Take note that I've only used a portion of the data you provided.

Ethelyn answered 2/10, 2014 at 12:3 Comment(11)
Thanks for the reply, My data is coming through the database, so the dropdownlist carry. I do not understand how I can do this.Zabrze
Well, instead of just echoing the <select> you could retrieve the data from the database and create a JSON object with the format that Select2 needs. Your newly created object will be the data to pass to select2.Irreplaceable
Again thank you, I do not have a good knowledge in jQuery to perform this operation, if you have another idea I appreciate it. hugsZabrze
Is it possible to go a dropdownlist and remake it in this structure?Zabrze
You don't need jQuery. If you are using PHP, you can create a multidimensional array with the keys id, name and children and then do a json_encode of the array. Your data variable, inside javascript, will be the result of json_encode. I am assuming to much because I don't know your entire process. If you like I can provide a complete answer in StackOverflow em Português after you add all the requirements and code (namely the code that queries the database.Irreplaceable
I'm working with VB.net, I think I saw something similar in my searches.Zabrze
I thought of something. Browse the dropdownlist and riding the date the way you can read again as the structure.Zabrze
No Primeiro desabilitar o Grupo de itens Seria UMA Opção, eu tentei Como abaixo, mas Localidade: Não funcionou. if ($(this).attr("value").indexOf('S') == 0) { $(this option).attr("disabled","disabled");Zabrze
Does anyone have any more suggestions?Zabrze
I tried that, but it did not work. $(this).attr("disabled") = true;Zabrze
Github issue link is dead.Java
S
1

I tried adding this as a comment to Saravanan's post above, but the length of the comment was too long, so consider this as an expansion to his post, and credit goes to him for giving me the idea.

This is a bit of a necro post from me, but just wanted to expand on how I implemented the above solution with the newer jquery format of $document.ready instead of $document.on. Slightly modified as well, since I have mine nested in a pageLoad, and thus the function is outside the pageLoad, and I used an attribute rather than a class. Important part though, is that I had to put both templateResult and templateSelection for it to work, as without the latter, nothing happened:

function pageLoad() {
    $(document).ready(function () {
        $(".multiple-group").select2({
            allowClear: true,
            closeOnSelect: false,
            templateResult: formatResult,
            templateSelection: formatResult
        });
    });    
}

function formatResult(node) {
    var level = 0;
    if (node.element !== undefined) {
        level = node.element.getAttribute("hierarchy-level");
        if (level.trim() !== '') {
            level = parseInt(level) - 1;
        }
    }

    var $result = $('<span style="padding-left:' + (15 * level) + 'px;">' + node.text + '</span>');
    return $result;
}
Seminar answered 28/10, 2017 at 17:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.