0

In Html have two select tags, the first contains all the worlds countries, the second contains only the countries selected by user.

<form action="/fixsongs.fix">
     <table>
                            <tr>
                                <td colspan="2">
                                    <label title="Potential Releases from these countries get their score boosted">
                                        Preferred Release Countries
                                    </label>
                                </td>
                            </tr>
                            <tr>
                                <td>
                                    <select id="preferred_countries_all" size="15" style="width:200px" multiple="multiple">
                                        <option value=" AF">Afghanistan</option><option value="AX">Åland Islands</option><option value="AL">Albania</option><option value="DZ">Algeria</option><option value="AS">American Samoa</option><option value="AD">Andorra</option><option value="AO">Angola</option><option value="AI">Anguilla</option><option value="AQ">Antarctica</option><option value="AG">Antigua and Barbuda</option><option value="AR">Argentina</option><option value="AM">Armenia</option><option value="AW">Aruba</option><option value="AU">Australia</option><option value="AT">Austria</option><option value="AZ">Azerbaijan</option><option value="BS">Bahamas</option><option value="BH">Bahrain</option>...<option value="ZW">Zimbabwe</option>
                                    </select>
                                </td>
                                <td>
                                    <button style="width:100px" type="button" id="preferred_countries_add" onclick="add_preferred_countries();">
                                        Add
                                    </button>
                                    <br>
                                    <button style="width:100px" type="button" id="preferred_countries_remove" onclick="remove_preferred_countries();">
                                        Remove
                                    </button>
                                </td>
                                <td>
                                    <select id="preferred_countries_selected" name="preferred_countries_selected" size="15" style="width:200px" multiple="multiple">
                                        <option value="GB">United Kingdom</option>
                                    </select>
                                </td>
                            </tr>
                        </table>
<input type="submit" value="Start">

The user selects them by highlighting and then click on button which invokes the following Javascript function.

function add_preferred_countries() {
     allCountries      = document.getElementById('preferred_countries_all');
     selectedCountries = document.getElementById('preferred_countries_selected');
     var length=$('#preferred_countries_all option:selected').length;
     if(length==0) { 
        return false;
     }

     $('#preferred_countries_all option:selected').each(function(){
        $('#preferred_countries_selected').append($(this));
     });
     //selectedCountries.value = "";


      for (var i = 0; i < selectedCountries.options.length; i++) { 
             selectedCountries.options[i].selected = selected; 
    } 
}

' That bits works fine, but I have realized that when I finally submit the form containing this and various other options that it will send items in the select list that are actually selected. So in the absence of a better solution I want to automatically select all values in the preferred_countries_selected whenever user adds new countries, so that when user submits form the preferred countries will be sent to server

I thought this would work, but has no effect

for (var i = 0; i < selectedCountries.options.length; i++) { 
                 selectedCountries.options[i].selected = selected; 

I know the existing function has some JQuery in it, but I would prefer pure javascript solution as I don't really understand JQuery syntax.

Ideally I would prefer to do this just as they press submit, but that is another question.

Paul Taylor
  • 13,411
  • 42
  • 184
  • 351

1 Answers1

1

You have some HTML validation issues with your table and you really should not use inline CSS or HTML event attributes (i.e. onclick) as they have many harmful side-effects.

See the inline comments in the code snippet below and note that you need the checked CSS pseudo-class, rather than selected:

// Get references to the two lists
var allCountries = document.getElementById('preferred_countries_all');
var selectedCountries = document.getElementById('preferred_countries_selected');

function add_preferred_countries(operation) {

  if(operation === "add"){
       // Get the selected countries from list one into an array
  var allPreferredSelected = Array.prototype.slice.call(allCountries.querySelectorAll('option:checked'));
     
  // Loop over the array
  allPreferredSelected.forEach(function(selOption){
    selectedCountries.appendChild(selOption);  // Add each to the second list
  });
 
  // Loop through the second list and select each option
  Array.prototype.slice.call(selectedCountries.querySelectorAll("option")).forEach(function(opt){
    opt.selected = "selected";
  });
    console.log("Item added");
  } else {
    // Do remove operation here
// Loop over the selected countries in the second list
Array.prototype.slice.call(selectedCountries.querySelectorAll("option:checked")).forEach(function(opt){
        selectedCountries.removeChild(opt);  // Remove country
    });

    console.log("Item removed");
  }
}

// Get the add and remove buttons into an array and loop over the array
Array.prototype.slice.call(document.querySelectorAll("button[id^='preferred_countries']")).forEach(function(btn){
  // Set up a click event handler for the button
  btn.addEventListener("click", function(){
    add_preferred_countries(this.dataset.action);  // Call the add/remove function with the right arg
  });
});
/* Do your styling separate from the HTML */
button[id^='preferred_countries'] { width:100px; }
select { width:200px; height:20em; }
<form action="/fixsongs.fix">
  <table>
    <tr>
      <td colspan="2">
        <span title="Potential Releases from these countries get their score boosted">
          Preferred Release Countries
        </span>
      </td>
    </tr>
    <tr>
      <td>
        <select id="preferred_countries_all" multiple="multiple">
          <option value=" AF">Afghanistan</option>
          <option value="AX">Åland Islands</option>
          <option value="AL">Albania</option>
          <option value="DZ">Algeria</option>
          <option value="AS">American Samoa</option>
          <option value="AD">Andorra</option>
          <option value="AO">Angola</option>
          <option value="AI">Anguilla</option>
          <option value="AQ">Antarctica</option>
          <option value="AG">Antigua and Barbuda</option>
          <option value="AR">Argentina</option><option value="AM">Armenia</option>
          <option value="AW">Aruba</option>
          <option value="AU">Australia</option>
          <option value="AT">Austria</option>
          <option value="AZ">Azerbaijan</option>
          <option value="BS">Bahamas</option><option value="BH">Bahrain</option>
          ...
          <option value="ZW">Zimbabwe</option>
        </select>
      </td>
      <td>
        <button type="button" id="preferred_countries_add" data-action="add">Add</button>
        <br>
        <button type="button" id="preferred_countries_remove" data-action="remove">Remove</button>
      </td>
      <td>
        <select id="preferred_countries_selected" name="preferred_countries_selected" multiple="multiple">
          <option value="GB">United Kingdom</option>
        </select>
      </td>
    </tr>
  </table>
  <input type="submit" value="Start">
</form>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • great that works, if you would like to explain it a little, for example how does it automatically remove items from first list I cant see the code that does that ? – Paul Taylor Jan 10 '18 at 21:21
  • @PaulTaylor I didn't add that code because your question didn't seem to specifically ask for that. I will update the answer to include it. – Scott Marcus Jan 10 '18 at 21:22
  • you misunderstood me, your original code DID remove item from first list when added to 2nd list but I couldnt understand why – Paul Taylor Jan 10 '18 at 21:35
  • @PaulTaylor Oh, that's the native behavior of `appendChild()`. It essentially moves the element to the location that you specify. This seems to be the correct behavior for what you are doing, but if you don't want that, you can clone the `option` (with the `.clone()` method) first and then `appendChild()` with the clone. – Scott Marcus Jan 10 '18 at 21:40
  • it does work apart from I would prefer if they were added back in alphabetical order instead of at the end, does your revised method do that ? – Paul Taylor Jan 10 '18 at 21:45
  • @PaulTaylor It does not, but again, I didn't see that as part of your original question. This would be done by keeping the `option` values in an array and then sorting the array and then re-organizing the `option`. – Scott Marcus Jan 10 '18 at 22:35
  • no it wasn't just occurred to me, thanks for your help – Paul Taylor Jan 11 '18 at 09:20