0

In my Java desktop application I have a list of items, and the user can change their order by selecting items and using the Up/Down buttons to change their position in the list.

enter image description here

What would be an equivalent way to do this in HTML? A <select> would not work because on mobile devices, selects only ever show one row regardless of what the size is set to.

Just a student
  • 10,560
  • 2
  • 41
  • 69
Paul Taylor
  • 13,411
  • 42
  • 184
  • 351
  • 1
    HTML has no native sortable control so you'd need a JavaScript one to reproduce that behavior – j08691 Jan 26 '18 at 21:58
  • @j08691 well can you give me a clue, and doesnt javscript just let you control html elements anyway, I.e I would need to construct form some html elements would i not ? – Paul Taylor Jan 26 '18 at 21:59
  • select with size attribute and optionally set height/width does not work? – bigless Jan 26 '18 at 22:27
  • 1
    @PaulTaylor — Well yes, but the elements you use to represent a list of things where order matters and a couple of buttons should be pretty obvious. – Quentin Jan 26 '18 at 22:30
  • @bigless well for another problem I had something else working fine but when I tried on ipad and phone it didn't show all the values and seemed to be a known issue. I raised this question https://stackoverflow.com/questions/48264919/what-do-i-use-instead-of-two-multiselect-boxes-in-html-so-works-on-phone-ipad – Paul Taylor Jan 26 '18 at 22:33
  • @j08691 hmm, not so obvious to me – Paul Taylor Jan 26 '18 at 22:35
  • @j08691 oh you mean an ordered list, and then i would use javascript to reorder the list and to submit the final list to the server, right, or perhaps an ordr list of input fields then they would be submitted anyway whn wrapped in form ? – Paul Taylor Jan 26 '18 at 22:39
  • or perhaps a sorted one column table would be better - https://www.w3schools.com/w3js/w3js_sort.asp – Paul Taylor Jan 26 '18 at 22:41
  • something small+standalone like Select2 or List.js is your best bet to retain no-js functionality and accessiblity, while not re-inventing the wheel. – dandavis Jan 30 '18 at 07:06

3 Answers3

1

Using JavaScript, you can quite easily implement such a control yourself. Here is a very quick and dirty example that works in modern browsers (most notably, not in Internet Explorer). Since mobile browsers do fire click events when handlers are attached directly to elements, this also works on mobile/touch devices. Of course, you may want to implement a slightly different layout for mobile devices, to make it easier to click elements. It may also be more intuitive to implement drag-and-dropping of elements to sort them on touch devices.

To make this work in a regular old form, a hidden input can be added and updated as well. To this end, we can add data attributes on the options, since they can be read easily with JavaScript. Another option would be to intercept the submit event of the form and doing the submit manually via AJAX, loading the event order then. The below demo implements the first option: populating a hidden input.

function orderInput(list, upButton, downButton, input) {
  updateInput(list, input);

  // enable selection of list elements
  for (let li of list.querySelectorAll('li')) {
    li.addEventListener('click', () => {
      for (let sibling of li.parentNode.children) {
        if (!sibling.isSameNode(li)) {
          sibling.classList.remove('selected');
        }
      }
      li.classList.toggle('selected');
    });
  }

  // enable moving an element up
  upButton.addEventListener('click', () => {
    var li = list.querySelector('li.selected');
    if (li.previousElementSibling !== null) {
      li.parentNode.insertBefore(li, li.previousElementSibling);
      updateInput(list, input);
    }
  });

  // enable moving an element down
  downButton.addEventListener('click', () => {
    var li = list.querySelector('li.selected');
    if (li.nextElementSibling !== null) {
      li.parentNode.insertBefore(li, li.nextElementSibling.nextElementSibling);
      updateInput(list, input);
    }
  });
}

function updateInput(list, input) {
  var values = [];
  for (let li of list.querySelectorAll('li')) {
    values.push(li.dataset.value);
  }
  input.value = values.join(';');
}

// instantiate on our fruits
orderInput(
  document.querySelector('ul'),
  document.getElementById('up'),
  document.getElementById('down'),
  document.querySelector('input[name="fruits"]')
);
ul {
  padding-left: 0;
  list-style-type: none;
  border: 1px solid darkgray;
}

li {
  padding: 2px 4px;
}

li:nth-child(even) {
  background-color: lightgray;
}

li.selected {
  background-color: blue;
  color: white;
}
<p>Click an item in the list to select it, change its place in the list using the up and down buttons.</p>
<button id="up">Up</button> - <button id="down">Down</button>
<ul>
  <li data-value="red-apple">Apple</li>
  <li data-value="yellow-banana">Banana</li>
  <li data-value="cherries">Cherry</li>
  <li data-value="d-fruit">Dragon Fruit</li>
  <li data-value="old-berry">Elderberry</li>
  <li data-value="not-a-figure">Fig</li>
  <li data-value="blue-grape">Grape</li>
</ul>
<input type="hidden" name="fruits" />
Just a student
  • 10,560
  • 2
  • 41
  • 69
  • Thats quite nice, but can you makeit so when you select it colours the background rather than the text. – Paul Taylor Jan 29 '18 at 20:57
  • That's easily done with some CSS, @PaulTaylor. I updated my answer. – Just a student Jan 30 '18 at 11:10
  • Hi, thankyou I have your example working in my code but have an additional issue, I need to store an internal value for each item, i.e it might display 'Apple' in English or 'Pomme' in French but I also need it to store internal value ) e.g APPLE which I can submit back to server – Paul Taylor Jan 30 '18 at 14:27
  • That sounds like a different question to me. Briefly: you can use [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes) and access those [with JavaScript](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset). – Just a student Jan 31 '18 at 09:26
  • Not really I just didnt think of this detail when writing question, with an Html Select Option element you have a display value and the actual value returned to server (e.g - Im essentially trying to replicate a Select option but so works with mobile and with extra functionality to change order. I will award you the bounty but if you could improve I would be grateful, – Paul Taylor Jan 31 '18 at 09:45
  • Thankyou I just wanted to confirm I have now implemented your solution and it is working correctly for me. – Paul Taylor Feb 02 '18 at 16:21
  • There is one small issue, I originally disabled the nth-child(even) CSS part but then I reneabled it and realized that if you try and select a greye dout line it remains grey, i.e the grey background overrides the select background. – Paul Taylor Feb 02 '18 at 22:21
  • That does not appear to happen in the snippet I included in my answer, so you must have made some other change(s), @PaulTaylor. It likely has to do with [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity). – Just a student Feb 04 '18 at 11:01
0

For the requirements that you want, try this.. In the function selected() you can write code as to what shpuld happen if an element is selected.

function selected(str){
 console.log(str+" is selected.");
 }
ul {
  position: absolute;
  top: 0;
  width: 200px;
  margin: 0;
  padding: 0;
  list-style: none;
}

ul a:hover {
  color: red;
  background: none;
}

li a {
  display: block;
  text-decoration: none;
}

li a:hover {
  text-decoration: none;
  color: red;
  background: rgba(255, 255, 255, 0.2);
}

li a:focus {
  text-decoration: none;
}
<ul style="height:4em; overflow-y:auto;">
  <li><a onclick="selected('1')">One</a></li>
  <li><a onclick="selected('2')">Two</a></li>
  <li><a onclick="selected('3')">Three</a></li>
  <li><a onclick="selected('4')">Four</a></li>
  <li><a onclick="selected('5')">Five</a></li>
</ul>
Harsha
  • 99
  • 1
  • 6
0

I recommend the use of JQuery plugin or small Javascript library like Sortable, that supports change the order using drag and even touch in portable devices.

Example: http://rubaxa.github.io/Sortable/

enter image description here

Eduardo Molteni
  • 38,786
  • 23
  • 141
  • 206
  • You recommend a jQuery plugin, then link to a library that states *no jQuery*. Also, it might be good to extend this answer with a small code example, ideally a runnable snippet. – Just a student Jan 29 '18 at 14:53
  • Hi Eduardo, that Sortable lib does look pretty good, however Im new to Javascript dev and finding the options a bit overwhelming, could you possibly code a small example for my use case. – Paul Taylor Jan 30 '18 at 14:12