Multiple selectbox using jQuery--HELP!

I am developing a python/django app and I have this form where I have two multiple select boxes. And I want to select an option from the left and move it to the right. I have two only to be more firendly tothe user. The selected options that are being saved are to the left select box. You will see to the following code how, I think it’s very simple.

I am using .each, because I somehow loop…but my code, I think, at each click repeats itself and keeps only the last one I have selected. I came to that conclusion after some tests where:
If I press CTRL and select as many as I want and click the button to “move” them to the “selected”, all of the items are being selected after I save the form.
If I select items by dragging the mouse, the same, all of the items are being selected.

Here is a screenshot. You can see the ids for each element:

And here is my code:

$("#users-to").click(function() {
    $("#id_users option:selected" ).each(function() {
        var a = $(this);
        $('#id_users_to').append(a.clone());
        $(this).attr('selected',true);
        $(this).hide();
        $('#update_abtn').attr('disabled',true);
        $('#delete_abtn').attr('disabled',true);
        $('#nousers').attr('disabled',true);
        $("#update_abtn").removeAttr('href');
        $("#delete_abtn").removeAttr('href');

    });

});

Please help!!!

HI danaev,

So that’s kinda hard to read. Please try formatting it by using three backticks prior to and after the code.

Also, there are a few concepts when using jQuery you’ll want to get used to and start using right away. The first is that, any time you use a jQuery method, you are calling a jQuery function. When you use jQuery to select something, there is an expense to that (in terms of execution time). So, if you’re going to use a selection more that once, it’s best to save it to a variable so that you can refer to it later without having to re-select it. A common approach is to start a collection variable with a $, as that is the abbreviation for jQuery.

So …

$users_from_btn = $( '#users-to' );
$users_to_btn = $( '#users-from' );

It just makes is easier to read later in the code and also means you are not asking the browser to re-select the elements. Things like this become quite important inside of a loop, which is where you are inside of that .each() call;

Another thing to know about is method chaining. That means you can use many Javascript and jQuery methods one right after the other in sequence like …

$a
   .attr( 'selected', true )
   .hide();

It makes for a simple stack to see the action you are operating on $a.

Finally, another important thing to know is that when you select something with jQuery, you are given back a “collection” - all items that matched the selector you provided. When you then call a jQuery method, in almost all cases it operates against the entire collection. So you often do not need an .each() call unless there really is something unique that needs to be done to each item in the collection.

I suggest reading about some of the most common jQuery “best practices”. It will help make your code more efficient and easier to read.

jQuery Best Practices

Now, as to the function itself … basically, on click of a button, you need to find any items that are selected in the source list, detach them, and append them to the destination list. Which button clicked determines what is the source and what is the destination list. Because the process of moving them from one list to another is identical, changing only based on which button is clicked, you can make a single function that both buttons call, altering only which list is passed in as source or destination arguments.

You should look into not just the .append() method, but also the .detach() method in jQuery as they are very useful here.

That’s about as far as I can go without writing out a solution, so … be warned … Major spoilers ahead.

function moveElements( selector, $source, $destination ){
   // SELECTOR IS A CSS SELECTOR THAT ALLOWS YOU TO DETERMINE WHICH ITEMS ARE SELECTED
   // SOURCE IS THE CURRENT LOCATION OF THE ITEMS
   /// DESTINATION IS WHERE YOU WANT THEM TO GO.

   const $elems = $source.find( selector ).detach();

   // NO ELEMENTS WERE SELECTED, NOTHING TO DO ...
   if ( !$elems.length )
      return;

   $destination.append( $elems );

}

const selector = 'option:selected'; // OR SOME SUCH CSS SELECTOR FOR FINDING SELECTED ITEMS
$left = $( '#id_users' );
$right = $( '#id_users_to' );

$( '#users_to' ).click( function(){
   moveElements( selector, $left, $right );
});

$( '#users_from' ).click( function(){
   moveElements( selector, $right, $left );
});

or something like that …

It should be in the neighborhood of what you are looking for.

In fact, I hacked together a quick pen where it is working just fine.

Working concept.

I left stuff out, like setting the disabled property based on whether or not there were any options selected, etc. Also, you said “move”, but in your code you are copying and then hiding the original. Mine does an actual move.

Anyway, I hope that helps.

Regards,
Micheal

1 Like

Thank you so much for taking th time to write this long and helpfull reply!
I think is pretty obvious to the whole programming thing!
To be honest I had completely forgot the optionto create a function and bind it to the button!

I will read your answer more carefully later and get back at you if I have any questions!

Thank you again so much!

Have a great day!!!

You’re welcome! Glad it helped.