ComboBox Sort Tutorial

ComboBox Sort Tutorial

ComboBox Sort Tutorial

All around the Internet, where there is tabular data presented, users instinctively look to that table’s header row and the column header cells (often “th” elements) to find ways to sort the data of the associated column’s rows, or in our ComboBox web application, that would be the presented order of option elements within the row data cell (usually “td” elements) “select” (dropdown) elements.

With today’s work, we do not buck that idea, placing our new sort functionalities, on top of the recent ComboBox Wikipedia Tutorial‘s progress …

  • to that same aforesaid mentioned “place” … tabular header row column “th” cells … but …
  • in a less commonly seen “form” … because we decide to turn “th” cell hardcodings into “a” element links (not underlined) that when clicked/tapped bring up a Javascript prompt window presenting a way for the user to decide (or not) among three new sort (of data) choices …
    1. Ascending (sort)
    2. Descending (sort)
    3. Original (as presented originally)

Can these “rearrangements of data” move with the “select” (dropdown) element? You bet they can! Now, we all know that “Chewing Gum” always sticks to the rails, and “Razor Blade” is always cutting it off, but who rounds the corner “sitting pretty”? Anyone, anyone? Yes, Laffit Pincay Junior, that “Global Attribute” has a wicked and withering home run! So much so, there’s time for the caller to formalize with that horse’s middle name …

… and “Global Data Attribute” wins by four lengths, in grand style!

Yes, these global data attributes are like having XML in your HTML armoury of data smarts. All we do, when called on to sort dropdown data is to store its Original order in a global attribute and then sort (that separate innerHTML content “option” subelements) off that, as called upon to do so (that “function thprompts” being called around the same time as document.body ‘s “onload” event) …


function askaboutsort(iw, iwc) {
var ioselo=null;
var sels=[], isels=0;
var curval='';
var ansis='';
var contarr=[], icont=0, incont='';
var ris='O';
sels=document.getElementsByTagName('select');
for (isels=0; isels<sels.length; isels++) {
if (('' + sels[isels].name) == ('selcombo' + iw).replace('o0','o') || ('' + sels[isels].name) == ('selcombo' + iw).replace('oJUNK0','o')) {
ioselo=sels[isels];
curval=ioselo.value;
}
}
if (ioselo) {
if (ioselo.outerHTML.indexOf(' data-content=') != -1) {
contarr=decodeURIComponent(ioselo.getAttribute('data-content')).split('</option>');
contarr.sort();
ansis=prompt('Do you want to sort Ascending or Descending column or restore Original order ' + iwc + '? ... A or D or O', '');
} else {
ris='A';
ioselo.setAttribute('data-content', encodeURIComponent(ioselo.innerHTML));
contarr=decodeURIComponent(ioselo.getAttribute('data-content')).split('</option>');
contarr.sort();
ansis=prompt('Do you want to sort Ascending or Descending column ' + iwc + '? ... A or D', '');
}
if (ansis == null) { ansis = ''; }
if ((ansis + ' ').toUpperCase().substring(0,1) == 'A') {
for (icont=0; icont<contarr.length; icont++) {
incont+=contarr[icont] + '</option>';
}
ioselo.innerHTML=incont;
ioselo.value=curval;
} else if ((ansis + ' ').toUpperCase().substring(0,1) == 'D') {
for (icont=eval(-1 + contarr.length); icont>=0; icont--) {
incont+=contarr[icont] + '</option>';
}
ioselo.innerHTML=incont;
ioselo.value=curval;
} else if ((ansis + ' ').toUpperCase().substring(0,1) == ris) {
ioselo.innerHTML=decodeURIComponent(ioselo.getAttribute('data-content'));
ioselo.value=curval;
}
}
}

function thprompts() {
var wasih='';
var ths=document.getElementsByTagName('th');
for (var iths=0; iths<ths.length; iths++) {
if (ths[iths].innerHTML.indexOf('<') == -1) {
wasih=ths[iths].innerHTML;
ths[iths].innerHTML='<a title="Click for some sorting options" style="cursor:pointer;text-decoration:none;" onclick="askaboutsort(' + iths + ",'" + wasih + "');" + '">' + wasih + '</a>';
}
}
}

Not too shabby?!

Only our changed external Javascript combobox.js called by combobox.htm web application needed to change for these new sorting functionalities.


Previous relevant ComboBox Wikipedia Tutorial is shown below.

ComboBox Wikipedia Tutorial

ComboBox Wikipedia Tutorial

Yesterday’s ComboBox Form Tutorial progress combined with today’s involvement of …

  • Wikipedia … thanks … via …
  • Inhouse PHP

… and can open up our ComboBox Form Table web application to the idea that the user can decide the table column names. How, pray tell? Have you noticed how great Wikipedia is at lists? There are lists of a huge number of concepts. So, think of plural words and use the new “dot” link in the header label of our web application to define your comma separated list of column names, and we’ll use the new PHP combobox.php to see “whether it flies” with a list distilled back to the user in the dropdown within the table data row cell’s ComboBox’s div/select element’s dropdown (ie. select) part.

Along the way we’ve started down the road of some mappings to those option elements of those ComboBox dropdown parts, that being …


<option value="[WikipediaBasedURL]">[WikipediaBasedLabel]</option>

… and in turn that has given us a pretty “static” (but none the less useful) “onchange” event logic idea to start using on ComboBox select (dropdown) element parts, as per …


function woit(sthis) {
if (sthis.value.indexOf(String.fromCharCode(104) + String.fromCharCode(116) + String.fromCharCode(116) + String.fromCharCode(112)) == 0) { // absolute URL value
window.open(sthis.value,'_blank','top=100,left=100,width=600,height=600');
}
}

And on the recall analysis of form (ie. user interactions) report we can use (good ‘ol) document.referrer to glean precise “name” in “name=value” paradigm alert box reporting, those being those user defined column headings to the ComboxBox Form Table …


<script type='text/javascript'>
var selc=" ", seli=0, selcombov=[], retrep='';
while (selc != '') {
selc = location.search.split('selcombo' + seli + '=')[1] ? decodeURIComponent(location.search.split('selcombo' + seli + '=')[1].split('&')[0]) : '';
if (selc != '') { selcombov.push('' + selc); retrep+='Value' + eval(1 + seli) + ' (set by user)=' + selc + String.fromCharCode(10); }
seli++;
}
if (retrep != '') {
if (('' + document.referrer).indexOf('?topics=') != -1) {
var cols=decodeURIComponent(('' + document.referrer).split('?topics=')[1]).split(',');
for (var iiu=1; iiu<=cols.length; iiu++) {
retrep=retrep.replace('Value' + iiu + ' ', cols[eval(-1 + iiu)] + ' ');
}
}

alert(retrep);
}
</script>

That being so, our changed external Javascript combobox.js called by our changed parent HTML combobox.htm web application might be worth your re-analysis.


Previous relevant ComboBox Form Tutorial is shown below.

ComboBox Form Tutorial

ComboBox Form Tutorial

Yesterday’s ComboBox Primer Tutorial got us working with new ComboBox div/select elements, but that was just a display mechanism, and not a “collection of data” mechanism. We could code for dynamic select “onchange” event and div “onblur” event logics, which we may allow for into the future, but today’s work is to have our external Javascript work with a parent HTML that has a …

  • form method=GET action=[“here’s looking at you kid”]
  • table with a header (ie. th cells) row … and
  • row with empty data cells (ie. td cells) …

    <table border=20>
    <tr><th>Integer</th><th>Lowercase</th><th>Uppercase</th></tr>
    <tr><td></td><td></td><td></td></tr>
    </table>
  • form submit button

… that can parrot back what a user selected for their ComboBox(es). The external Javascript changes ensure …

  • a mechanism now exists for multiple calls of the external Javascript from the parent HTML … exemplified by …

    <script type='text/javascript' src='combobox.js?ddlist=1,2,3,4' defer></script>
    <script type='text/javascript' src='combobox.js?ddlist=a,b,c,d' defer></script>
    <script type='text/javascript' src='combobox.js?ddlist=A,B,C,D' defer></script>
  • and the default place to hold those resultant ComboBox div/select elements is to empty innerHTML elements (such as those td data cells above) … and …
  • ComboBox div/select elements now get created with a “name” attribute (meaning selections are passed back to [here’s looking at you kid”]
  • ComboBox div/select elements now get class “combobox” applied to them to aid with parent HTML styling CSS such as …

    <style>
    div.combobox { background-color:yellow; }
    select.combobox { background-color:pink; width:95%; }
    </style>

    … means they slot into place into the parent HTML form and be self-returnable (ie. action=[“here’s looking at you kid”])

… so that there can be better practical use made of these ComboBox div/select elements used by our changed external Javascript combobox.js called by our changed parent HTML combobox.htm web application


Previous relevant ComboBox Primer Tutorial is shown below.

ComboBox Primer Tutorial

ComboBox Primer Tutorial

Do you remember a blog posting a couple of days ago called Favourites Poll Email Moderation Contenteditable Tutorial featuring …

contenteditable global attribute magic

? Well, that started me rethinking on a very long-running personal desire with our web application work. In the Windows early GUI desktop applications going back to VB.Net and C++ in the latter 1900 years there was a GUI control called “ComboBox” (class) that never failed to impress me. It matches a lot of needs to be presented with a static list of choices in mind, but then want to extend that list as time and situation changes over time. A “ComboBox” can handle it, it being that combination of …

  • dropdown (static) list … and …
  • textbox “extender”

… all manageable sounding in today’s web application wooooorrrrrlllllld, especially, in our minds, having defer
and contenteditable as useful concepts for the latter item above. And so a …

  • dropdown (select) element … nested within a …
  • div contenteditable=true

… paradigm is the basis for our combobox.js external Javascript to feature an Object Oriented looking Javascript Class …


// combobox.js
// External Javascript to extend some HTML like combobox.html allowing for a dynamically created HTML div element "combobox" (ie. dropdown + div contenteditable=true)
// November, 2020
// Called via ...
// <script type='text/javascript' src='combobox.js' defer></script>
// ... or dropdown populated example as per ...
// <script type='text/javascript' src='combobox.js?ddlist=Asia,Africa,Europe,North%20America,South%20America,Australia,Antarctica' defer></script>

class Droptext {
constructor(combobox) {
this.ele = document.createElement('div');
this.ele.id = ('' + combobox).split(';')[0];
if (('' + combobox).indexOf(';') != -1) {
this.ele.setAttribute('data-dropinnards', ('' + combobox).split(';')[1]);
this.ele.setAttribute('data-optionval', "<option value=''></option>");
this.ele.setAttribute('data-focusaway', "<input style=position:absolute;top:-200px;left:-200px; type=text value=></input>");
this.ele.setAttribute('contenteditable', true);
this.ele.innerHTML = ('' + combobox).split(';')[1]; // + "<input style=position:absolute;top:-200px;left:-200px; type=text value=></input>";
}
}
present() {
return this.ele.outerHTML.replace('><select', ' onblur=" var odiv=event.target; var optval=event.target.getAttribute(' + "'" + 'data-optionval' + "'" + '); var fway=event.target.getAttribute(' + "'" + 'data-focusaway' + "'" + '); var umytype=event.target.innerHTML; var alltogether=event.target.getAttribute(' + "'" + 'data-dropinnards' + "'" + ').split(String.fromCharCode(60) + ' + "'" + '/select' + "'" + ')[0]; if (umytype.trim().length == 0) { odiv.innerHTML = event.target.getAttribute(' + "'" + 'data-dropinnards' + "'" + '); } else if (alltogether.indexOf(String.fromCharCode(62) + umytype + String.fromCharCode(60)) != -1) { odiv.innerHTML = alltogether.replace(String.fromCharCode(62) + umytype + String.fromCharCode(60), ' + "' selected'" + ' + String.fromCharCode(62) + umytype + String.fromCharCode(60)) + event.target.getAttribute(' + "'" + 'data-focusaway' + "'" + '); } else { alltogether+=optval.replace(String.fromCharCode(39), String.fromCharCode(39) + umytype).replace(String.fromCharCode(62), String.fromCharCode(62) + umytype); alltogether+=String.fromCharCode(60) + ' + "'" + '/select' + "'" + ' + String.fromCharCode(62); odiv.innerHTML = fway; odiv.innerHTML = alltogether.replace(String.fromCharCode(62) + umytype + String.fromCharCode(60), ' + "' selected'" + ' + String.fromCharCode(62) + umytype + String.fromCharCode(60)) + event.target.getAttribute(' + "'" + 'data-focusaway' + "'" + '); odiv.setAttribute(' + "'" + 'data-dropinnards' + "'" + ',alltogether); } " onkeypress=" event.target.setAttribute(' + "'" + 'data-sofar' + "'" + ', event.target.innerHTML); " onkeydown=" if (event.target.innerHTML.indexOf(String.fromCharCode(60)) != -1) { event.target.innerHTML=' + "''" + '; } "><select');
}
}

class Contents extends Droptext {
constructor(combobox, mod) {
if (('' + combobox) == '') {
var iinn=0;
while (document.getElementById('combobox' + iinn)) {
iinn++;
}
combobox = 'combobox' + iinn;
}
super((combobox + ';' + mod));
this.dropinnards = mod;
}
show() {
return this.present() + "<input style=position:absolute;top:-200px;left:-200px; type=text value=></input>"; // + ', it is a ' + this.dropinnards;
}
}

… and middlemanperson external Javascript …


var ihs = "";
var selconts = location.search.split('ddlist=')[1] ? (ihs + decodeURIComponent(location.search.split('ddlist=')[1].split('&')[0])).split(',') : (ihs + "<select><option value=''></option><option value='Red'>Red</option><option value='Blue'>Blue</option><option value='Yellow'>Yellow</option></select>").split(',');
if (document.head.innerHTML.replace('&ddlist=','?ddlist=').indexOf('?ddlist=') != -1) {
ihs = decodeURIComponent(document.head.replace('&ddlist=','?ddlist=').innerHTML.split('?ddlist=')[1].split('&')[0].split('"')[0].split("'")[0]); // + ',';
if (ihs.trim() != '') { selconts = ihs.split(','); }
}
if (selconts[0].indexOf('<select') != 0) {
var selcont = "<select>";
for (var jiip=0; jiip<selconts.length; jiip++) {
if (selconts[jiip].indexOf('<select') != 0) {
selcont += '<option value="' + selconts[jiip] + '">' + selconts[jiip] + '</option>';
}
}
selcont += "</select>";
mycombobox = new Contents("", selcont);
} else {
mycombobox = new Contents("", selconts[0]);
}
var obody = document.body;
if (document.getElementById('demo')) {
obody = document.getElementById('demo');
} else {
var ofound = false;
var obs = document.getElementsByTagName('div');
for (var iip=0; iip<obs.length; iip++) {
if (obs[iip].innerHTML == '') {
obody = obs[iip];
ofound = true;
}
}
if (!ofound) {
obody.innerHTML += '<div id=demo></div>';
obody = document.getElementById('demo');
}
}
obody.innerHTML += mycombobox.show();

… that suits the need of our proof of concept calling HTML combobox.html live run code …


<!doctype html>
<html>
<head>
<script type='text/javascript' src='combobox.js' defer></script>
</head>
<body>
<div id='demo'></div>
</body>
</html>

Intervening at the “onkeydown” event of the hosting HTML div contenteditable=true is the essence of why the “ComboBox” can be (quite a bit, but not totally) like that forerunner “ComboBox” VB.Net GUI control.

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

This entry was posted in eLearning, Event-Driven Programming, Tutorials and tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *