Multiselect options order


Topic: Multiselect options order

Juric pro premium asked 8 months ago

Hi, I was pretty positive suprised, as I found that, the order, which user select options in the mdb multiselect will correctly shown in the input field. So if we have e.g. select with option1 option2 option3

and if a user clicks at first option2, then option 1 then we see: "option2, option1" if a user clicks at first option 1 then option 2, then we see: ""option1, option2"

do everything is very fine to that moment. But if I get values like $('#myId').val() we get all options like option1, option2.etc. So the order is lost. But for me it is very important. Do you have any solution or advice on that problem please?


Mikołaj Smoleński staff answered 8 months ago

Hi Juric,

Unfortunately, You can't get sorted values in this way.

Best regards


Juric pro premium answered 8 months ago

Hi,

yes, I know, that I can't get order this way. I have asked if you can help me to get the right order. I mean, your framework can mention the click order of the selected options, which is great. So you probably can provide a solution to get them in right order.

Thanks


Juric pro premium answered 8 months ago

I just saw, that I can't find my own solution without your help.

My idea was, in worst case (if you don't help me), to develop my own procedure, which would get values from the input element (where are they displayed) and then to order my values (which I got by $(elem).val() by that order.

But I see, that the input element has no values at all, I dont understand, why I see any values displayed at all. What I have for example is:

<input type="text" class="select-dropdown" readonly="true" data-activates="select-options-70b8a0cb-512e-4cfa-8980-6822c654a8e1" value="">

So I am completely confused, how I can get the displayed values at all. Please help me to find a solution, the order is critical. Thanks


Mikołaj Smoleński staff answered 7 months ago

Hi Juric,

There is a way to achieve array with that order, but You'll have to change some code in mdb.js file. Please find the following part of code:

this.$materialOptionsList.find('li:not(.optgroup):not(.select-toggle-all)').eq(optionIndex).toggleClass('active');
this.$nativeSelect.find('option').eq(optionIndex).prop('selected', !isSelected);

this._setValueToMaterialSelect();

After this code You can add the value getter, e.x:

console.log(this.valuesSelected);

Best regards


Juric pro premium answered 7 months ago

Hi, thanks for answering. I have found this line in mdb.js file, but I cannot understand, how exactly I could get the values by order.

I suppose, it is possible to add a new method to materialSelect object. But I don't understand how exactly

Something like (???):

{
      key: "_getValuesByOrder",
      value: function _getValuesByOrder(optionIndex) {
        var selectedValueIndex = this.valuesSelected.indexOf(optionIndex);
        var isSelected = selectedValueIndex !== -1;

        if (!isSelected) {
          this.valuesSelected.push(optionIndex);
        } else {
          this.valuesSelected.splice(selectedValueIndex, 1);
        }

        this.$materialOptionsList.find('li:not(.optgroup):not(.select-toggle-all)').eq(optionIndex).toggleClass('active');
        this.$nativeSelect.find('option').eq(optionIndex).prop('selected', !isSelected);

        // this._setValueToMaterialSelect();

        return this.valuesSelected;
      }
    }

And how I then get the values from my Javascript function? Could you post an example please, what exactly should I change or add in mbd.js and how I then use it? E.f. I have a multiselect elements with id='mySelectCustomer' How I then get it: $('#mySelectCustomer').??? Thanks


Mikołaj Smoleński staff answered 7 months ago

Instead of console.log in my example You can define a new variable, e.x.:

orderedOptions = this.valuesSelected;

and then in Your custom js file You can access it like this:

  $('.mdb-select').materialSelect();
  $('.mdb-select').on('change', function() {
    console.log(orderedOptions);
  })

Best regards


Juric pro premium answered 7 months ago

Hi, thanks for your answer.

Where should I put orderedOptions = this.valuesSelected;

Is it in mdb.js file? If yes, where exactly?


Juric pro premium answered 7 months ago

Please provide detailed piece of code and advice where exactly in mdb.js I should pu it.

And then, how do I get the values from my page without using onupdate event. I suppose it should be something like

$('#myMultiselect').????

Thanks


Mikołaj Smoleński staff answered 7 months ago

As I wrote above, You need to put this code instead of console.log in my first example, so it will look like this:

this.$materialOptionsList.find('li:not(.optgroup):not(.select-toggle-all)').eq(optionIndex).toggleClass('active');
this.$nativeSelect.find('option').eq(optionIndex).prop('selected', !isSelected);

this._setValueToMaterialSelect();
orderedOptions = this.valuesSelected;

And then in Your own custom js file (but imported after mdb.js). You can access orderedOptions after each select change.

Your html file should look like this:

 <script type="text/javascript" src="js/mdb.js"></script>
 <script> 
    $(document).ready(function () { 

      $('.mdb-select').materialSelect();
      $('.mdb-select').on('change', function() {
        console.log(orderedOptions);
      })

    });
 </script>

Best regards


Juric pro premium answered 7 months ago

Hi,

I have an impression, you did not understand, what I have written.

at first, I don't want to use onchange event. I have many select elements with diferrent IDs. I would like to het values from them on right order by my own event (for example RUN button).

But just to check, if your code is working Ihave put the line

orderedOptions = this.valuesSelected;

into mdb.js and made like you suggested:

function initMultiSelect() {
    if(allMultiselectLoaded()) {
        // log('initializing of MDB multiselect ...');
        $('.mdb-select').materialSelect();
        $('.mdb-select').on('change', function() {
        console.log(orderedOptions);
      })
    }
}

and onchange I have in console exceptions:

Uncaught ReferenceError: orderedOptions is not defined

which is OK for me, cause I don't understand what orderedOptions variable is, it is never defined anywhere, even not in mdb.js. And of course it is not defined in my page. So it is something you missing .

Please try to understand, what I need and explain me detailed what to do. Thanks

I am waiting for resolving this issue a few days already, and don't understand, why. Thanks


Mikołaj Smoleński staff answered 7 months ago

I fully understand what Your writing about. You just needed to make some modifications to make it work and I thought You can handle it without a problem.

Here's the full code. Please analyze it carefully:

In Your html file:

<select class="mdb-select md-form" multiple>
  <option value="" disabled selected>Choose your country</option>
  <option value="1">USA</option>
  <option value="2">Germany</option>
  <option value="3">France</option>
  <option value="4">Poland</option>
  <option value="5">Japan</option>
</select>
<button class="btn-save btn btn-primary btn-sm">Save</button>

<button class="btn btn-primary run">Run</button>

(...)

  <script>
    var orderedOptions;
  </script>
  <script type="text/javascript" src="js/mdb.js"></script>
  <script type="text/javascript" src="js/addons/datatables.min.js"></script>
  <script> 
    $(document).ready(function () { 

      $('.mdb-select').materialSelect();
      $('.run').on('click', function() {
        console.log(orderedOptions)
      })

    });
  </script>

and in mdb.js:

}, {
  key: "_toggleSelectedValue",
  value: function _toggleSelectedValue(optionIndex) {
    var selectedValueIndex = this.valuesSelected.indexOf(optionIndex);
    var isSelected = selectedValueIndex !== -1;

    if (!isSelected) {
      this.valuesSelected.push(optionIndex);
    } else {
      this.valuesSelected.splice(selectedValueIndex, 1);
    }

    this.$materialOptionsList.find('li:not(.optgroup):not(.select-toggle-all)').eq(optionIndex).toggleClass('active');
    this.$nativeSelect.find('option').eq(optionIndex).prop('selected', !isSelected);

            this._setValueToMaterialSelect();
            orderedOptions = this.valuesSelected;

    return !isSelected;
  }
}, {

And now, after clicking "Run" button You have access to the ordered array.

Best regards


Juric pro premium answered 7 months ago

Hi,

I implemented as you suggested. It does not work for me. In console, I see "undefined"

Even if it would work, it is a kind of dirty solution. Cause as I said, I have many multiselect elements on one page, so corresponding your design, I probably need to define many variables like var orderedOptions1, orderedOptions2...

for every multiselect element, right?

In reallity I generate all thet elements dynamically, so I don't know exactly how many elements I would have (it depends on parameters), so I would never know how may variables I need to define. And I have no idea, what I would need to change in mdb.js file in that case (if I have many multiselect elements in one page).

But again, even that solution with one multiselect does not work. I think, a good was would be to provide your embedded solution (your own methods) to get ordered values from the multiselect.

So the user could select, what he needs: ordered values or e.g. not ordered ones. Is that possible?


Juric pro premium answered 7 months ago

Hi, I must admit., that my post over I have done without checking on a simple static html file. I checked that on my pretty complex environment with dynamically generated elements.

Now I have checked it on a simple static html with only one multselect element: it is working!

So sorry, I have said, that it doesn't work.

But I have still questions (prev. post) how to use this solution with multiple elements and with dynamically created ones (so I don't know how many elements it would be generated).


Mikołaj Smoleński staff answered 7 months ago

Hi,

My idea is to add an unique class or id to each select and then update the array by this attribute. For example:

In html file:

  <div class="container"> 

    <select class="mdb-select first md-form" multiple>
      <option value="" disabled selected>Choose your country</option>
      <option value="1">USA</option>
      <option value="2">Germany</option>
      <option value="3">France</option>
      <option value="4">Poland</option>
      <option value="5">Japan</option>
    </select>
    <button class="btn-save btn btn-primary btn-sm">Save</button>

    <button class="btn btn-primary run">Run</button>

  </div>
  <div class="container">

    <select class="mdb-select second md-form" multiple>
      <option value="" disabled selected>Choose your country</option>
      <option value="1">USA</option>
      <option value="2">Germany</option>
      <option value="3">France</option>
      <option value="4">Poland</option>
      <option value="5">Japan</option>
    </select>
    <button class="btn-save btn btn-primary btn-sm">Save</button>

    <button class="btn btn-primary run2">Run</button>

  </div>

(...)

  <script>
    var orderedOptions;
    var orderedOptions2;
  </script>
  <script type="text/javascript" src="js/mdb.js"></script>
  <script type="text/javascript" src="js/addons/datatables.min.js"></script>
  <script> 
    $(document).ready(function () { 

      $('.mdb-select').materialSelect();
      $('.run').on('click', function() {
        console.log(orderedOptions)
      })
      $('.run2').on('click', function() {
        console.log(orderedOptions2)
      })

    });
  </script>

And in mdb.js:

this._setValueToMaterialSelect();

if ($(this)[0].$nativeSelect.hasClass('first'))   orderedOptions = this.valuesSelected;
if ($(this)[0].$nativeSelect.hasClass('second')) orderedOptions2 = this.valuesSelected;

return !isSelected;

Best regards


Juric pro premium answered 7 months ago

I don't like this idea:

at first: it is not dynamic at all. I still need to know how many elements I have.

second: I should manipulate central mdb.js file with many variables, which are defined outside of it. It looks not good.

And third: even this would not work in my enveronment, cause I have many iframes, each of them has reference to mdb.js. So it is not possible to use one mdb.js, cause in one iframe it could be 3 multiselect in another one 5 etc.

I don't understand, why you can't provide method to get ordered elements without defining any variables outside of mdb.js? What we need is an acces to "this.valuesSelected" from outside (from my local html).

It should be possible I think. Please search for another solution. Thanks


Mikołaj Smoleński staff commented 7 months ago

Unfortunately it's not such an easy case and I can't provide You the better solution.

Best regards


Juric pro premium answered 7 months ago

Hi, please consider more general solution (at least in the very next version). You can discuss it with another developers, please. It is just very unclear why you cannot provide it, cause the visible order is already working.

  1. As a premium support user we await more quickly response on our questions. Please check our issues:

https://mdbootstrap.com/support/?user=51781

There are a few of them, which were not answered many days. Please provide help Thanks


Juric pro premium answered 7 months ago

Another problem with your solution:orderedOptions has only indexes like [2,4,1] instead of values


Mikołaj Smoleński staff answered 7 months ago

Ok Juric,

I've added Your issue to our list of most important tasks. We'll consider an update in one of the next releases.

I also reminded the team about Your latest opened issues.

Best regards


Juric pro premium answered 7 months ago

Hi,

as I found a workaround (with your help) I will close this topic.

Just to mention: I am not very satisfied with it, cause it is still workaround and I should use my own version of mdb.js, which takes additionally and anwanted efforts.

As far I understand, you will consider to provide a general solution in the next release. Thanks


Status

Closed

Specification of the issue
  • User: Pro
  • Premium support: Yes
  • Technology: jQuery
  • MDB Version: 4.6.1
  • Device: Desktop
  • Browser: IE 11, Chrome
  • OS: Windows 10
  • Provided sample code: No
  • Provided link: No