I'm trying to make a custom compare callback function for the Javascript array.sort
method. It should return a value depending on user input.
When that callback function is called, it should wait until the user clicks a button. Depending on the clicked button the function would know which of the two elements is bigger and return the corresponding result (1 or -1).
The only way I know to wait for user input is with an event listener function, but I don't know how to adapt this to the custom function I have to pass to the array.sort()
method.
Here is the code I'm trying with; I know this code won't work:
var array=["a","b","c"];
array.sort(function(a,b){
var result;
$("#button1").click(function(){
result = 1;
});
$("#button2").click(function(){
result = -1;
});
return result;
}
I'm starting to think it's impossible to use the array.sort
function for this purpose.
Is there a way to do this?
You could do this the ugly way, by making use of the window.confirm method, which has the behaviour to wait with the further execution of your code until the user closes the pop-up by either choosing OK or Cancel:
array=["a","b","c"];
array.sort(function(a,b){
var a_before_b = confirm("'" + a + "' will be sorted before '" + b
+ "'. Cancel to order differently.");
return a_before_b ? -1 : 1;
});
document.body.innerHTML = '<p>Array sorted: ' + array + '</p>';
<p>You will get 2 to 3 pop up dialogs to sort [a, b, c]</p>
To have the user answer via normal interaction, not via modal dialogs, and still use the standard sort method, is a harder task.
One idea would be to keep a list of answers given, and repeat the sort each time an new answer is available, feeding those answers via the sort callback function.
Once a comparison comes up for which no answer was yet given, you would then present that comparison to the user, and complete the rest of the sort with any order. That sorted array will be ignored, up until the moment you have all answers for all comparisons.
The code is quite long, mostly because of the interaction with the page:
var array = ['a', 'b', 'c'];
var answers = [];
var questionTemplate = "Order '#' before or after '#'?";
var answerTemplate = "The array is sorted. Result: #.";
function logMsg(msg) {
$($('#log')[0].insertRow(-1).insertCell(-1)).text(msg);
}
function answer(order) {
// keep track of answers
answers.push(order);
// show answers also in a log table
logMsg($('#question').text() + ' - ' + (order<0? 'Before' : 'After'));
askNext();
}
function askNext() {
var arrayCopy = array.slice(0); // take real copy
var questionNo = -1;
arrayCopy.sort(function(a,b){
questionNo++
if (questionNo < answers.length) {
// we already asked this, so use that answer
return answers[questionNo];
}
if (questionNo == answers.length) {
// put question to user:
$('#question').text(questionTemplate.replace('#', a).replace('#', b));
}
// don't care for now, just finish it. We need first to
// get an answer, and will then restart the sort.
return -1;
});
if (array.length == answers.length) {
// Array is now sorted according to answers:
// Hide question section
$('#questionDiv').hide();
// Show the result
logMsg(answerTemplate.replace('#', arrayCopy));
}
}
function reset() {
$('#array').text(array);
$('#questionDiv').show()
$('#log').html(''); // empty log table
answers = [];
askNext();
}
// Set up click handlers
$('#reset').click(reset);
$('#before').click(answer.bind(null, -1));
$('#after').click(answer.bind(null, 1));
reset();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>The array <span id="array"></span> will be sorted by asking you questions:</p>
<table id="log"></table>
<div id="questionDiv">
<p id="question" style="font-weight: bold"></p>
<button id="before">Before</button><button id="after">After</button>
</div>
<button id="reset">Restart</button>